POJ 3225 Help with Intervals (线段树,区间成段更新)
Help with Intervals
Description LogLoader, Inc. is a company specialized in providing products for analyzing logs. While Ikki is working on graduation design, he is also engaged in an internship at LogLoader. Among his tasks, one is to write a module for manipulating time intervals, which have confused him a lot. Now he badly needs your help. In discrete mathematics, you have studied several basic set operations, namely union, intersection, relative complementation and symmetric difference, which naturally apply to the specialization of sets as intervals.. For your quick reference they are summarized in the table below:
Ikki has abstracted the interval operations emerging from his job as a tiny programming language. He wants you to implement an interpreter for him. The language maintains a set S, which starts out empty and is modified as specified by the following commands:
Input The input contains exactly one test case, which consists of between 0 and 65,535 (inclusive) commands of the language. Each command occupies a single line and appears like
where End of file (EOF) indicates the end of input. Output Output the set S as it is after the last command is executed as the union of a minimal collection of disjoint intervals. The intervals should be printed on one line separated by single spaces and appear in increasing order of their endpoints. If S is empty, just print “ Sample Input U [1,5] D [3,3] S [2,4] C (1,5) I (2,3] Sample Output (2,3) Source |
题意:给一个全局为0~65536的区间,一开始区间s为空间,然后不断地对区间s进行并上一个区间,交一个区间,减一个区间,用一个区间减去s,还有异或下两个区间。。。
题意:区间操作,交,并,补等
思路:
我们一个一个操作来分析:(用0和1表示是否包含区间,-1表示该区间内既有包含又有不包含)
U:把区间[l,r]覆盖成1
I:把[-∞,l)(r,∞]覆盖成0
D:把区间[l,r]覆盖成0
C:把[-∞,l)(r,∞]覆盖成0 , 且[l,r]区间0/1互换
S:[l,r]区间0/1互换
分析:这题的各个操作都可以用线段树的成段更新在log(65536*2)的时间内完成
U:并上一个区间,也就是,将这个区间置1就行
I:交上一个区间[l,r],将区间[-∞,l)和(r,∞]置0
D:减去一个区间,将这个区间置0就行
C:用一个区间[l,r]减去s,将区间[-∞,l)和(r,∞]置0,区间[l,r]取反就行
S:求异或,区间[l,r]取反就行
现在上面的所有操作都在理论上解决掉了,而区间的开或闭这个直接把所有区间乘2,对于左边的开区间要加1,右边减1
这题注意a==0的情况。。。导致自己RE了很久。。。
#include <stdio.h> #include <iostream> #include <algorithm> #include <string.h> using namespace std; const int MAXN=131072; struct Node { int l,r; int flag;// flag==0表示全部没有覆盖,flag==1表示全部被覆盖,其余为-1 int rev;//rec==1表示取反,rec==0表示不变,只有flag==-1时候rev才有作用 }segTree[MAXN*4]; void Build(int i,int l,int r)//建树 { segTree[i].l=l; segTree[i].r=r; segTree[i].flag=0; segTree[i].rev=0; if(l==r)return; int mid=(l+r)>>1; Build(i<<1,l,mid); Build((i<<1)|1,mid+1,r); } void T(int i)//对结点i取反 { if(segTree[i].flag!=-1)segTree[i].flag^=1; else segTree[i].rev^=1; } void push_down(int i)//往下更新 { if(segTree[i].flag!=-1) { segTree[i<<1].flag=segTree[(i<<1)|1].flag=segTree[i].flag; segTree[i].flag=-1; segTree[i<<1].rev=segTree[(i<<1)|1].rev=0; } if(segTree[i].rev) { T(i<<1); T((i<<1)|1); segTree[i].rev=0; } } void update(int i,int l,int r,int op) { if(l<=segTree[i].l && r>=segTree[i].r) { if(op==0 || op==1) { segTree[i].flag=op; segTree[i].rev=0; } else { T(i); } return; } push_down(i); int mid=(segTree[i].l+segTree[i].r)>>1; if(r<=mid)update(i<<1,l,r,op); else if(l>mid)update((i<<1)|1,l,r,op); else { update(i<<1,l,mid,op); update((i<<1)|1,mid+1,r,op); } } int cov[2*MAXN+10]; void query(int i) { if(segTree[i].flag==1) { for(int j=segTree[i].l;j<=segTree[i].r;j++) cov[j]=segTree[i].flag; return; } else if(segTree[i].flag==0) return; if(segTree[i].l==segTree[i].r)return; push_down(i); query(i<<1); query((i<<1)|1); } int main() { // freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); char op,lc,rc; Build(1,0,MAXN); int a,b; while(scanf("%c %c%d,%d%c",&op,&lc,&a,&b,&rc)!=EOF) { //把值乘于2,左开加1,右开减1 a=a<<1; if(lc=='(')a++; b=b<<1; if(rc==')')b--; if(a>b)//空集 { if(op=='I' || op=='C')update(1,0,MAXN,0); } else { if(op=='U')update(1,a,b,1);//把这个区间全部置1 else if(op=='I')//把0~a-1 b+1~MAXN置0 { if(a>0)update(1,0,a-1,0);//这里要注意,a==0的情况,一直RE呢 if(b<MAXN)update(1,b+1,MAXN,0); } else if(op=='D')update(1,a,b,0);//区间置0 else if(op=='C')//把0~a-1 b+1~MAXN置0 区间取反 { if(a>0)update(1,0,a-1,0); if(b<MAXN)update(1,b+1,MAXN,0); update(1,a,b,2); } else update(1,a,b,2);//区间取反 } getchar(); } memset(cov,0,sizeof(cov)); query(1); bool first=true; for(int i=0;i<MAXN;i++) { if(cov[i]==1 && (i==0 || (i>0&&cov[i-1]==0) ))a=i; if(cov[i]==1 && (i==MAXN-1 || cov[i+1]==0)) { if(first)first=false; else printf(" "); if(a%2)printf("("); else printf("["); printf("%d,",a/2); printf("%d",(i+1)/2); if(i%2)printf(")"); else printf("]"); } } if(first)printf("empty set"); printf("\n"); return 0; }
代码2:
不用结构体。。。看别人的仿写的
#include <stdio.h> #include <iostream> #include <algorithm> #include <string.h> using namespace std; const int MAXN=131072; int flag[MAXN<<2],rev[MAXN<<2]; void T(int i)//对结点i取反 { if(flag[i]!=-1)flag[i]^=1; else rev[i]^=1; } void push_down(int i) { if(flag[i]!=-1) { flag[i<<1]=flag[(i<<1)|1]=flag[i]; flag[i]=-1; rev[i<<1]=rev[(i<<1)|1]=0; } if(rev[i]) { T(i<<1); T((i<<1)|1); rev[i]=0; } } void update(int i,int l,int r,int op,int L,int R) { if(l<=L && r>=R) { //printf("l:%d r:%d %d\n",l,r,i); if(op==0 || op==1) { flag[i]=op; rev[i]=0; } else { T(i); } return; } push_down(i); int mid=(L+R)>>1; if(r<=mid)update(i<<1,l,r,op,L,mid); else if(l>mid)update((i<<1)|1,l,r,op,mid+1,R); else { update(i<<1,l,mid,op,L,mid); update((i<<1)|1,mid+1,r,op,mid+1,R); } } int cov[2*MAXN+10]; void query(int i,int L,int R) { if(flag[i]==1) { for(int j=L;j<=R;j++) { cov[j]=flag[i]; } return; } else if(flag[i]==0) return; if(L==R)return; push_down(i); int mid=(L+R)>>1; query(i<<1,L,mid); query((i<<1)|1,mid+1,R); } int main() { // freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); char op,lc,rc; int a,b; memset(flag,0,sizeof(flag)); memset(rev,0,sizeof(rev)); while(scanf("%c %c%d,%d%c\n",&op,&lc,&a,&b,&rc)!=EOF) { a=a<<1; if(lc=='(')a++; b=b<<1; if(rc==')')b--; if(a>b)//空集 { if(op=='I' || op=='C')update(1,0,MAXN,0,0,MAXN); } else { if(op=='U')update(1,a,b,1,0,MAXN); else if(op=='I') { if(a>0)update(1,0,a-1,0,0,MAXN); if(b<MAXN)update(1,b+1,MAXN,0,0,MAXN); } else if(op=='D')update(1,a,b,0,0,MAXN); else if(op=='C') { if(a>0)update(1,0,a-1,0,0,MAXN); if(b<MAXN)update(1,b+1,MAXN,0,0,MAXN); update(1,a,b,2,0,MAXN); } else update(1,a,b,2,0,MAXN); } } memset(cov,0,sizeof(cov)); query(1,0,MAXN); bool first=true; for(int i=0;i<MAXN;i++) { if(cov[i]==1 && (i==0 || (i>0&&cov[i-1]==0) ))a=i; if(cov[i]==1 && (i==MAXN-1 || cov[i+1]==0)) { if(first)first=false; else printf(" "); if(a%2)printf("("); else printf("["); printf("%d,",a/2); printf("%d",(i+1)/2); if(i%2)printf(")"); else printf("]"); } } if(first)printf("empty set"); printf("\n"); return 0; }