Help with Intervals 线段树区间更新
Posted qq2210446939
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Help with Intervals 线段树区间更新相关的知识,希望对你有一定的参考价值。
题意:给你一个初始为空的集合,对其进行5种操作若干遍,输出最终的集合。
设S为一开始的集合,则: U T 表示 S=S∪T
I T 表示 S=S∩T
D T 表示 S=S-T
C T 表示 S=T-S
S T 表示 S=S异或T
思路:用线段树模拟区间操作,叶子结点为1代表区间存在,0代表不存在,因为区间有开区间和闭区间两种,单单用叶子结点模拟自然数实现不了开区间,所以我们对坐标系×2扩大,原来的闭区间整数点对应扩大后的偶数点,1 2 3 4 5 变成2 4 6 8 10,原来的开区间例如(2,3】,扩大后变成(4,6】,再将开区间的端点相中心靠拢(4,6】->【5,6】由于新坐标系的偶数对应原坐标系,则新坐标系的奇数就可以用来实现开区间,然后区间更新实现操作即可。
具体做法:设区间T为【L,R】,U T就是将T区间全更新为1。I T就是将【0,L-1】和【R+1,maxn】更新为0,因为求交集,则T区间以外的区间就不能存在,T区间之内的任由原来的S怎么地,就实现了交集。D T 就是将区间T变为0。对于C T,则是将T区间翻转,将T区间外变成0,因为是T-S,则T区间外一定是0,T区间内,S内就变为0,外就是1,就是翻转嘛。对于异或,S有的T没有的,T有的S没有的,这样的目标区间只需要将T区间翻转即可,T区间外的自然不影响,则S有的T没有的得到了保留,对于T区间内,有S的地方变为了0,没S的地方变成了1,所以即可达到操作!
AC代码:
#include<iostream> #include<stdio.h> #include<string.h> using namespace std; const int maxn=2e5+10; int col[maxn<<2]; void pushdown(int rt){ if(col[rt]==2){ col[rt<<1]=1-col[rt<<1]; col[rt<<1|1]=1-col[rt<<1|1]; col[rt]=-1; } if(col[rt]!=-1){ col[rt<<1]=col[rt<<1|1]=col[rt]; col[rt]=-1; } } void check(){ cout<<"********************** "; for(int i=1;i<=50;i++) cout<<col[i]<<" "; cout<<" ******************** "; } void updata(int L,int R,int val,int l,int r,int rt){ if(L<=l&&r<=R){ if(val==2) col[rt]=1-col[rt]; else col[rt]=val; return; } pushdown(rt); int m=l+r>>1; if(L<=m) updata(L,R,val,l,m,rt<<1); if(R>m) updata(L,R,val,m+1,r,rt<<1|1); } int search(int pos,int l,int r,int rt){ if(l==r){ return col[rt]; } int m=l+r>>1; pushdown(rt); if(pos<=m) return search(pos,l,m,rt<<1); else return search(pos,m+1,r,rt<<1|1); } int main() { int a,b; char s,sl,sr,sm; memset(col,0,sizeof(col)); while(~scanf(" %c %c%d %c%d %c",&s,&sl,&a,&sm,&b,&sr)){ a<<=1; b<<=1; if(sl==‘(‘) a++; if(sr==‘)‘) b--; if(s==‘U‘) updata(a,b,1,0,maxn,1); if(s==‘I‘){ if(a>0) updata(0,a-1,0,0,maxn,1); updata(b+1,maxn,0,0,maxn,1); } if(s==‘D‘) updata(a,b,0,0,maxn,1); if(s==‘C‘){ updata(a,b,2,0,maxn,1); if(a>0) updata(0,a-1,0,0,maxn,1); updata(b+1,maxn,0,0,maxn,1); } if(s==‘S‘){ updata(a,b,2,0,maxn,1); } } int flag=0,k=0; for(int i=0;i<maxn;i++){ int now=search(i,0,maxn,1); if(k==0&&now==1){ if(i%2==0) printf("[%d,",i/2); else printf("(%d,",i/2); k=1; flag=1; } if(k==1&&now==0){ int index=i-1;//最后一个1的下标 if(index%2==0) printf("%d] ",(index+1)/2); else printf("%d) ",(index+1)/2);//如果是奇数,则表示的是index+1这个右端点的开区间 //若index=5 则原区间是...,3) k=0; } } if(flag==0) printf("empty set "); return 0; } /* U [1,5] D [3,3] S [2,4] C (1,5) I (2,3] */
以上是关于Help with Intervals 线段树区间更新的主要内容,如果未能解决你的问题,请参考以下文章