hdu 3397(线段树区间合并)
2011-09-17 14:44
239 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3397
题意描述:给你一个0和1组成的序列,后给你五个操作,0 a,b,表示将区间a到b的值变为0,1 a,b表示将区间a到b的值变为1,2 a,b,表示将区间a到b的序列取反,3 a,b表示查询区间a到b中所有1的个数,4 a,b表示查询区间a到b中连续1的个数,之后给出每个查询,每个查询输出需要的结果。
分析:更新线段树中的区间线段必须保证更新是正确的,也就是说在向下传递和向上回溯时更新区间值时一定要保证更新的正确性,此题线段树中维护lmax,rmax,max,len,id,分别表示区间的左边连续1的个数,区间右边连续1的个数,区间中连续最大1的个数,区间的长度,id作为延迟的标记,若为1表示该区间所有的的值都为1,若为0,表示该区间所有的值都为0,若为-1,表示该区间中既存在1也存在0;当操作为0或1时这个好办,直接将当前覆盖区间的标记,若操作为2时,直接更新到某个全是1或者全是0的覆盖区间,然后将其取反后返回,回溯更新,
查询的时候遇到某个区间全是1则返回r-l+1,若全是0则返回0,否则若操作为4时,该区间已经被覆盖,那么直接返回区间的max
唉~,线段树的题目,感觉就是描述不清楚
代码:
题意描述:给你一个0和1组成的序列,后给你五个操作,0 a,b,表示将区间a到b的值变为0,1 a,b表示将区间a到b的值变为1,2 a,b,表示将区间a到b的序列取反,3 a,b表示查询区间a到b中所有1的个数,4 a,b表示查询区间a到b中连续1的个数,之后给出每个查询,每个查询输出需要的结果。
分析:更新线段树中的区间线段必须保证更新是正确的,也就是说在向下传递和向上回溯时更新区间值时一定要保证更新的正确性,此题线段树中维护lmax,rmax,max,len,id,分别表示区间的左边连续1的个数,区间右边连续1的个数,区间中连续最大1的个数,区间的长度,id作为延迟的标记,若为1表示该区间所有的的值都为1,若为0,表示该区间所有的值都为0,若为-1,表示该区间中既存在1也存在0;当操作为0或1时这个好办,直接将当前覆盖区间的标记,若操作为2时,直接更新到某个全是1或者全是0的覆盖区间,然后将其取反后返回,回溯更新,
查询的时候遇到某个区间全是1则返回r-l+1,若全是0则返回0,否则若操作为4时,该区间已经被覆盖,那么直接返回区间的max
唉~,线段树的题目,感觉就是描述不清楚
代码:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=100005; struct node { int l,r,len; //len表示区间的长度 int lmax,rmax,max; //分别表示区间左边连续的1的个数,区间右边连续1的个数,区间最多连续1的个数 int id; //延迟标记,为0表示区间中全为0,若为1表示区间中全为1,若为-1则表示区间中有0和1 }tree[N*4]; int a ; int Max(int a,int b) { return a>b?a:b; } int Min(int a,int b) { return a>b?b:a; } //建立线段树 void bulid(int rt, int l, int r) { tree[rt].l=l; tree[rt].r=r; tree[rt].len=r-l+1; tree[rt].lmax=0; tree[rt].rmax=0; tree[rt].max=0; tree[rt].id=-1; if(l==r) { if(a[l])//若为1则更新标记 {tree[rt].lmax=1;tree[rt].rmax=1;tree[rt].max=1;tree[rt].id=1;} else tree[rt].id=0; return; } int mid=(l+r)>>1; bulid(2*rt,l,mid); //建立左子树 bulid(2*rt+1,mid+1,r); //建立右子树 // 回溯更新区间左边连续最大1的个数 if(tree[2*rt].lmax==tree[2*rt].len) tree[rt].lmax=tree[2*rt].lmax+tree[2*rt+1].lmax; else tree[rt].lmax=tree[2*rt].lmax; //更新区间右边连续最大1的个数 if(tree[2*rt+1].rmax==tree[2*rt+1].len) tree[rt].rmax=tree[2*rt+1].rmax+tree[2*rt].rmax; else tree[rt].rmax=tree[2*rt+1].rmax; //更新区间中连续最多1的个数 tree[rt].max=Max(tree[2*rt].rmax+tree[2*rt+1].lmax,Max(tree[2*rt].max,tree[2*rt+1].max)); //更新延迟标记 if(tree[2*rt].id==0&&tree[2*rt+1].id==0)tree[rt].id=0; if(tree[2*rt].id==1&&tree[2*rt+1].id==1)tree[rt].id=1; } //建父亲的信息传递到其儿子 void pushdown(int rt) { if(tree[rt].id==-1) return; int id=tree[rt].id; //更新左右孩子的区间值 tree[rt].id=-1; tree[2*rt].id=id; tree[2*rt+1].id=id; tree[2*rt].max=tree[2*rt].len*id; tree[2*rt].lmax=tree[2*rt].len*id; tree[2*rt].rmax=tree[2*rt].len*id; tree[2*rt+1].max=tree[2*rt+1].len*id; tree[2*rt+1].lmax=tree[2*rt+1].len*id; tree[2*rt+1].rmax=tree[2*rt+1].len*id; } void update(int rt, int l, int r, int op) { if(tree[rt].l <=l && tree[rt].r >=r&&op==tree[rt].id)//若访问区间比查询区间大,且他们的操作方式都一样,则直接返回 return; if(op<2) {//若过操作方式为0/1时 if(tree[rt].l==l&&tree[rt].r==r) //找到覆盖的区间后直接更新 { tree[rt].id=op; tree[rt].max=tree[rt].len*op; tree[rt].lmax=tree[rt].len*op; tree[rt].rmax=tree[rt].len*op; return; } } else if(op==2) { //若延迟标记为0或者1时且该区间刚好能够被查询区间覆盖则更新区间值 if(tree[rt].id!=-1&&tree[rt].len==r-l+1) { tree[rt].id=(tree[rt].id+1)%2; tree[rt].max = tree[rt].len*tree[rt].id; tree[rt].lmax = tree[rt].len*tree[rt].id; tree[rt].rmax = tree[rt].len*tree[rt].id; return; } } pushdown(rt);//传递父亲节点的值 int mid=(tree[rt].l+tree[rt].r)>>1; if(r <=mid)update(2*rt,l,r,op); else if(l>mid)update(2*rt+1,l,r,op); else {update(2*rt,l,mid,op); update(2*rt+1,mid+1,r,op);} //回溯更新区间的值 if(tree[2*rt].lmax==tree[2*rt].len) tree[rt].lmax=tree[2*rt].lmax+tree[2*rt+1].lmax; else tree[rt].lmax=tree[2*rt].lmax; if(tree[2*rt+1].rmax==tree[2*rt+1].len) tree[rt].rmax=tree[2*rt+1].rmax+tree[2*rt].rmax; else tree[rt].rmax=tree[2*rt+1].rmax; tree[rt].max=Max(tree[2*rt].rmax+tree[2*rt+1].lmax,Max(tree[2*rt].max,tree[2*rt+1].max)); if(tree[2*rt].id==0&&tree[2*rt+1].id==0)tree[rt].id=0; if(tree[2*rt].id==1&&tree[2*rt+1].id==1)tree[rt].id=1; } int search(int rt, int l,int r, int op) { if(tree[rt].id==1)//表示该区间全是1则返回查询区间的长度 return r-l+1; else if(tree[rt].id==0) // 若区间权为0则返回0 return 0; else if(tree[rt].l==l&&tree[rt].r==r&&op==4) //若区间刚好被覆盖,且要查询区间连续最大1的个数,则直接返回 return tree[rt].max; int mid = (tree[rt].l+tree[rt].r)>>1; if(r<=mid)return search(2*rt,l,r,op); else if(l>mid) return search(2*rt+1,l,r,op); else { if(op==3)return search(2*rt,l,mid,op)+search(2*rt+1,mid+1,r,op); else { int ans=Min(tree[2*rt].rmax,mid-l+1); int ans1=Min(tree[2*rt+1].lmax,r-mid); return Max(ans+ans1, Max(search(2*rt,l,mid,op),search(2*rt+1,mid+1,r,op))); } } } void print(int rt) { printf("%d %d %d %d\n",tree[rt].l, tree[rt].r, tree[rt].id, tree[rt].max); if(tree[rt].l==tree[rt].r) return; print(2*rt); print(2*rt+1); } int main() { int t,n,i,q,op,l,r; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&q); for(i=0;i<n;i++) scanf("%d",&a[i]); bulid(1,0,n-1); for(i=0;i<q;i++) { scanf("%d%d%d",&op,&l,&r); //if(op==4)print(1); if(op<=2) update(1,l,r,op); else printf("%d\n",search(1,l,r,op)); } } return 0; }
相关文章推荐
- http://acm.hdu.edu.cn/showproblem.php?pid=3308&&线段树之区间合并
- POJ3667:Hotel(线段树区间合并)
- POJ 3667 Hotel 线段树 区间合并 入门题
- hihoCoder#1116-计算[线段树+合并区间]
- CF 46 D Parking Lot(线段树区间合并)
- poj 3667 Hotel(线段树中级,区间合并)
- HDU - 4553 约会安排(线段树 区间合并)
- URAL 1019. Line Painting 线段树 区间合并 离散化
- hdu 1540 线段树(区间合并入门)
- hdu 3308 LCIS(线段树单点更新+区间合并)中等难度的题目
- LA3938——线段树区间合并
- 【线段树】 SPOJ 1043 Can you answer these queries I 区间合并
- 杭电3308 LCIS(线段树区间合并)
- 线段树区间合并 hdu3308 LCIS
- hdoj 1540 Tunnel Warfare 【线段树 区间合并】
- poj 3667 Hotel(线段树,区间合并)
- hdu 3308 LCIS(线段树区间合并)
- HDU5316 Magician 线段树区间合并
- LA3938 "Ray, Pass me the dishes!" (线段树区间合并)
- UESTC 94 - Bracket Sequence(线段树+区间合并)