线段树之成段更新( 需要用到延迟标记,简单来说就是每次更新的时候不要更新到底,用延迟标记使得更新延迟到下次需要更新or询问到的时候)
HDU 1698
链接: http://acm.hdu.edu.cn/showproblem.php?pid=1698
线段树功能:update:成段替换 (由于只query一次总区间,所以可以直接输出1结点的信息)
- <span style="font-size:18px;">#include<iostream>
- #include<cstdio>
- #include<cstring>
- #define lson l,m,rt<<1
- #define rson m+1,r,rt<<1|1
- using namespace std;
- const int maxn=100001;
- int sum[maxn<<2];
- int col[maxn<<2];
- void pushUP(int rt) //当前节点信息更新给父节点
- {
- sum[rt]=sum[rt<<1]+sum[rt<<1|1];
- }
- void pushdown(int rt,int m) //当前节点信息更新给儿子节点
- {
- if(col[rt])
- {
- col[rt<<1]=col[rt<<1|1]=col[rt];
- sum[rt<<1]=(m-(m>>1))*col[rt];
- sum[rt<<1|1]=(m>>1)*col[rt];
- col[rt]=0;
- }
- }
- void build(int l,int r,int rt) //建立线段树
- {
- col[rt]=0;
- sum[rt]=1;
- if(l==r)
- return;
- int m=(l+r)/2;
- build(lson);
- build(rson);
- pushUP(rt);
- }
- void update(int L,int R,int c,int l,int r,int rt) //成段替换,由于只query一次总区间,所以可以直接输出1节点的信息
- {
- if(L<=l&&r<=R)
- {
- col[rt]=c;
- sum[rt]=(r-l+1)*c;
- return;
- }
- pushdown(rt,r-l+1);
- int m=(l+r)/2;
- if(L<=m) update(L,R,c,lson);
- if(R>m) update(L,R,c,rson);
- pushUP(rt);
- }
- int main()
- {
- int T,n,m;
- scanf("%d",&T);
- for(int cas=1;cas<=T;cas++)
- {
- scanf("%d%d",&n,&m);
- build(1,n,1);;
- while(m--)
- {
- int a,b,c;
- scanf("%d%d%d",&a,&b,&c);
- update(a,b,c,1,n,1);
- }
- printf("Case %d: The total value of the hook is %d.\n",cas , sum[1]);
- }
- return 0;
- }</span>
poj 3468
链接:http://poj.org/problem?id=3468
题解:很好的一个区间更新的线段树的模型,线段树的功能,update成段增减,query区间求和,关键在于对pushdown的理解,当扩展区间与节点上区间完全吻合时,停止向下
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #define lson l,m,rt<<1
- #define rson m+1,r,rt<<1|1
- using namespace std;
- const int maxn=100001;
- long long sum[maxn<<2],col[maxn<<2];
- void pushUP(int rt)
- {
- sum[rt]=sum[rt<<1]+sum[rt<<1|1];
- }
- void pushdown(int rt,int m)
- {
- if(col[rt])
- {
- col[rt<<1]+=col[rt];
- col[rt<<1|1]+=col[rt];
- sum[rt<<1]+=(m-(m>>1))*col[rt];
- sum[rt<<1|1]+=(m>>1)*col[rt];
- col[rt]=0;
- }
- }
- void build(int l,int r,int rt)
- {
- col[rt]=0;
- if(l==r)
- {
- scanf("%lld",&sum[rt]);
- return;
- }
- int m=(l+r)/2;
- build(lson);
- build(rson);
- pushUP(rt);
- }
- void update(int L,int R,int c,int l,int r,int rt) //成段增减
- {
- if(L<=l&&r<=R)
- {
- col[rt]+=c;
- sum[rt]+=c*(r-l+1);
- return;
- }
- pushdown(rt,r-l+1);
- int m=(l+r)/2;
- if(L<=m) update(L,R,c,lson);
- if(R>m) update(L,R,c,rson);
- pushUP(rt);
- }
- long long query(int L,int R,int l,int r,int rt) //区间求和
- {
- if(L<=l&&r<=R)
- return sum[rt];
- pushdown(rt,r-l+1);
- long long ret=0;
- int m=(l+r)/2;
- if(L<=m) ret+=query(L,R,lson);
- if(R>m) ret+=query(L,R,rson);
- return ret;
- }
- int main()
- {
- int n,q;
- scanf("%d%d",&n,&q);
- build(1,n,1);
- while(q--)
- {
- int a,b,c;
- char op[2];
- scanf("%s",op);
- if(op[0]=='Q')
- {
- scanf("%d%d",&a,&b);
- printf("%lld\n",query(a,b,1,n,1));
- }
- else
- {
- scanf("%d%d%d",&a,&b,&c);
- update(a,b,c,1,n,1);
- }
- }
- return 0;
- }
poj2528(线段树+离散化)
题目链接:http://poj.org/problem?id=2528
题目解答:
离散化就是压缩区间,使原有的长区间映射到新的短区间,但是区间压缩前后的覆盖关系不变。举个例子:
有一条1到10的数轴(长度为9),给定4个区间[2,4] [3,6] [8,10] [6,9],覆盖关系就是后者覆盖前者,每个区间染色依次为 1 2 3 4。
现在我们抽取这4个区间的8个端点,2 4 3 6 8 10 6 9
然后删除相同的端点,这里相同的端点为6,则剩下2 4 3 6 8 10 9
对其升序排序,得2 3 4 6 8 9 10
然后建立映射
2 3 4 6 8 9 10
↓ ↓ ↓ ↓ ↓ ↓ ↓
1 2 3 4 5 6 7
那么新的4个区间为 [1,3] [2,4] [5,7] [4,6],覆盖关系没有被改变。新数轴为1到7,即原数轴的长度从9压缩到6,显然构造[1,7]的线段树比构造[1,10]的线段树更省空间,搜索也更快,但是求解的结果却是一致的。
离散化时有一点必须要注意的,就是必须先剔除相同端点后再排序,这样可以减少参与排序元素的个数,节省时间。
由于此题数据较大,所以此题要用离散化
线段树功能:update:成段替换 query:简单hash
- #include<iostream>
- #include <cstdio>
- #include <cstring>
- #include <algorithm>
- using namespace std;
- #define lson l , m , rt << 1
- #define rson m + 1 , r , rt << 1 | 1
- const int maxn = 11111;
- bool hash[maxn];
- int li[maxn] , ri[maxn];
- int X[maxn*3];
- int col[maxn<<4];
- int cnt;
- void PushDown(int rt) //更新到儿子节点(此处为覆盖,所以用这种方法更新)
- {
- if (col[rt] != -1)
- {
- col[rt<<1] = col[rt<<1|1] = col[rt];
- col[rt] = -1;
- }
- }
- void update(int L,int R,int c,int l,int r,int rt) //成段替换
- {
- if (L <= l && r <= R) {
- col[rt] = c;
- return ;
- }
- PushDown(rt);
- int m = (l + r) >> 1;
- if (L <= m) update(L , R , c , lson);
- if (m < R) update(L , R , c , rson);
- }
- void query(int l,int r,int rt) //简单的hash,cnt统计离散化以后的长度
- {
- if (col[rt] != -1)
- {
- if (!hash[col[rt]]) cnt ++;
- hash[ col[rt] ] = true;
- return ;
- }
- if (l == r) return ;
- int m = (l + r) >> 1;
- query(lson);
- query(rson);
- }
- int Bin(int key,int n,int X[]) //二分查找的过程
- {
- int l = 0 , r = n - 1;
- while (l <= r)
- {
- int m = (l + r) >> 1;
- if (X[m] == key) return m;
- if (X[m] < key) l = m + 1;
- else r = m - 1;
- }
- return -1;
- }
- int main()
- {
- int T , n;
- scanf("%d",&T);
- while (T --)
- {
- scanf("%d",&n);
- int nn = 0;
- for (int i = 0 ; i < n ; i ++) //离散化的过程
- {
- scanf("%d%d",&li[i] , &ri[i]);
- X[nn++] = li[i];
- X[nn++] = ri[i];
- }
- sort(X , X + nn);
- int m = 1;
- for (int i = 1 ; i < nn; i ++)
- {
- if (X[i] != X[i-1]) X[m ++] = X[i];
- }
- for (int i = m - 1 ; i > 0 ; i --)
- {
- if (X[i] != X[i-1] + 1) X[m ++] = X[i-1] + 1;
- }
- sort(X , X + m);
- memset(col , -1 , sizeof(col));
- for (int i = 0 ; i < n ; i ++)
- {
- int l = Bin(li[i], m, X);
- int r = Bin(ri[i], m, X);
- update(l, r, i, 0, m - 1, 1);
- }
- cnt = 0;
- memset(hash, false, sizeof(hash));
- query(0, m - 1, 1);
- printf("%d\n",cnt);
- }
- return 0;
- }
线段树之成段更新( 需要用到延迟标记,简单来说就是每次更新的时候不要更新到底,用延迟标记使得更新延迟到下次需要更新or询问到的时候)的更多相关文章
- Codeforces295A - Greg and Array(线段树的成段更新)
题目大意 给定一个序列a[1],a[2]--a[n] 接下来给出m种操作,每种操作是以下形式的: l r d 表示把区间[l,r]内的每一个数都加上一个值d 之后有k个操作,每个操作是以下形式的: x ...
- hdu 1698 Just a Hook(线段树之 成段更新)
Just a Hook Time Limit: ...
- hdu 4614 Vases and Flowers(线段树:成段更新)
线段树裸题.自己写复杂了,准确说是没想清楚就敲了. 先是建点为已插花之和,其实和未插花是一个道理,可是开始是小绕,后来滚雪球了,跪了. 重新建图,分解询问1为:找出真正插画的开始点和终止点,做成段更新 ...
- POJ 2777 Count Color(线段树之成段更新)
Count Color Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 33311 Accepted: 10058 Descrip ...
- POJ3648 A Simple Problem with Integers(线段树之成段更新。入门题)
A Simple Problem with Integers Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 53169 Acc ...
- hdu1698 Just a Hook 线段树:成段替换,总区间求和
转载请注明出处:http://blog.csdn.net/u012860063 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1698 Problem ...
- hdu 1698 线段树(成段替换 区间求和)
一条钩子由许多小钩子组成 更新一段小钩子 变成铜银金 价值分别变成1 2 3 输出最后的总价值 Sample Input11021 5 25 9 3 Sample OutputCase 1: The ...
- POJ 3468 A Simple Problem with Integers //线段树的成段更新
A Simple Problem with Integers Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 59046 ...
- poj2528 Mayor's posters(线段树之成段更新)
Mayor's posters Time Limit: 1000MSMemory Limit: 65536K Total Submissions: 37346Accepted: 10864 Descr ...
随机推荐
- Lighttpd 服务器的安装
https://www.cnblogs.com/rongfengliang/articles/3503228.html
- AC日记——栈 洛谷 P1044
题目背景 栈是计算机中经典的数据结构,简单的说,栈就是限制在一端进行插入删除操作的线性表. 栈有两种最重要的操作,即pop(从栈顶弹出一个元素)和push(将一个元素进栈). 栈的重要性不言自明,任何 ...
- es6 递归 tree
function loop(data) { let office = data.map(item => { if(item.type == '1' ||item.type == '2') { i ...
- python异常捕获异常堆栈输出
python异常捕获异常堆栈输出 学习了:https://blog.csdn.net/chris_grass/article/details/77927902 import traceback def ...
- hadoop2.7.1 nutch2.3 二次开发windows环境
Hadoop windows编译: 能够略过这一段,直接下载hadoo2.7.1 bin文件.我的资源里有终于生成的winutils.exe和一些native code,放在bin文件夹即可了 參 ...
- HTML5已定稿:将彻底颠覆原生应用
2007年W3C(万维网联盟)立项HTML5,直至2014年10月底.这个长达八年的规范最终正式封稿. 过去这些年.HTML5颠覆了PC互联网的格局,优化了移动互联网的体验,接下来.HTML5将颠覆原 ...
- 关于文件与文件系统的压缩与打包命令-Linux(笔记)
1.gzip : 压缩命令 gzip [-cdtv#] 文件名称 (后缀为.gz) -c :将压缩的数据输出到屏幕上,可通过数据流重定向处理 -d : 解压缩的參数 -v : 能够显示源文件/压缩文件 ...
- OpenStack Live Migration
About live migration of KVM virtual machines with NFS storage, from Mirantis blog: click this link w ...
- 作为iOS程序员,最核心的60%能力有哪些?
作为iOS程序员,最核心的60%能力有哪些? 一个合格的iOS程序员需要掌握多少核心技能?你和专业的开发工程师的差距有多大?你现在的水平能开发一个功能完整性能高效的iOS APP吗?一起来看看下面 ...
- 给大二学生——能够再坚持一年的ACM
[来信] 我是大二学生,就读于一所非常普通的大学.学校ACM基本零起步,去年才開始搞,我大一大二花了非常多时间搞acm,如今不太想放弃.但学校基本没人愿意搞这个. 非常快就要大三了,我一直在纠结要不要 ...