solution-cf817f
CF817F题解
posted on 2022-01-08 08:09:05 | under 题解 | source
本题看完后我们发现它应该需要维护 3 种操作:
将 l 到 r 的区间用 1 覆盖
将 l 到 r 的区间用 0 覆盖
将 l 到 r 的区间取反
区间的初始值都为 0。
在每次操作后输出第一个 0 的下标。
对于区间修改的问题,很明显是线段树。
只不过。。。细节多得让人疯
1. 对于懒惰标记,我们有 4 种情况:
-
0:表示没有标记
-
1:表示要用 0 覆盖
-
2:表示要用 1 覆盖
-
3:表示要取反
所以,下降懒惰标记也。。。
void down(int q){
if(c[q].p&&c[q].l!=c[q].r){//有标记
int l=q<<1,r=q<<1|1;
if(c[q].p!=3){//这个懒惰标记是覆盖
c[l].p=c[q].p;c[l].v=(c[q].p-1)*(c[l].r-c[l].l+1);
c[r].p=c[q].p;c[r].v=(c[q].p-1)*(c[r].r-c[r].l+1);//那就直接覆盖
}
else{//这个标记是反转
if(c[l].p==0)c[l].v=c[l].r-c[l].l+1-c[l].v,c[l].p=3;//没有就直接修改
else if(c[l].p==1)c[l].v=c[l].r-c[l].l+1,c[l].p=2;//如果用0覆盖,就换成用1覆盖
else if(c[l].p==2)c[l].v=0,c[l].p=1;//如果用1覆盖,就换成用0覆盖
else c[l].v=c[l].r-c[l].l+1-c[l].v,c[l].p=0;//如果标记了反转,直接改
if(c[r].p==0)c[r].v=c[r].r-c[r].l+1-c[r].v,c[r].p=3;
else if(c[r].p==1)c[r].v=c[r].r-c[r].l+1,c[r].p=2;
else if(c[r].p==2)c[r].v=0,c[r].p=1;
else c[r].v=c[r].r-c[r].l+1-c[r].v,c[r].p=0;//同理
}
}
c[q].p=0;
}
2.对于区间修改,我们有两种:
1.覆盖
void Add(int q,int l,int r,int x){
if(l<=c[q].l&&c[q].r<=r){c[q].p=x;c[q].v=(x-1)*(c[q].r-c[q].l+1);return;}//修改整个区间,直接改懒惰标记
down(q);
int mid=c[q].l+c[q].r>>1;
if(l<=mid)Add(q<<1,l,r,x);
if(mid<r)Add(q<<1|1,l,r,x);
c[q].v=c[q<<1].v+c[q<<1|1].v;
}
2.反转
void Swap(int q,int l,int r){
if(l<=c[q].l&&c[q].r<=r){//反转整个区间
if(c[q].p==1||c[q].p==2){//原本是覆盖,那就反着覆盖
c[q].v=c[q].r-c[q].l+1-c[q].v;
c[q].p=(c[q].p==1?2:1);
}
else{//原本是反转或没有,直接改
c[q].v=c[q].r-c[q].l+1-c[q].v;
c[q].p=(c[q].p==0?3:0);
}
return;
}
down(q);
int mid=c[q].l+c[q].r>>1;
if(l<=mid)Swap(q<<1,l,r);
if(mid<r)Swap(q<<1|1,l,r);
c[q].v=c[q<<1].v+c[q<<1|1].v;
}
3.查询
int Gets(int q){
if(c[q].v==0)return c[q].l;//如果这个区间都是0,返回左端点
if(c[q].v==c[q].r-c[q].l+1)return 0;//如果都是1,无解
down(q);//下传
int sum=Gets(q<<1);//先左后右
if(sum!=0)return sum;
sum=Gets(q<<1|1);
return sum;
}
4.主函数
scanf("%lld",&n);
for(int i=1;i<=n;i++){
scanf("%lld%lld%lld",&a[i].t,&a[i].l,&a[i].r);
p[(i-1)*4+1]=a[i].l;
p[(i-1)*4+2]=a[i].l-1;//加入l-1(加入更优的答案)
p[(i-1)*4+3]=a[i].r;
p[i*4]=a[i].r+1;//加入r+1保证有答案
}
p[n*4+1]=1;//一定要有1!!!
sort(p+1,p+n*4+2);
for(int i=1;i<=n*4+1;i++){if(p[i]!=p[i-1])M_A[p[i]]=++tot,M_B[tot]=p[i];}//离散化
T.Build(1,1,tot);
for(int i=1;i<=n;i++){
if(a[i].t!=3)T.Add(1,M_A[a[i].l],M_A[a[i].r],(a[i].t==1?2:1));
else T.Swap(1,M_A[a[i].l],M_A[a[i].r]);//按要求操作
printf("%lld\n",M_B[T.Gets(1)]);//输出
}
这是总代码(无注释)

浙公网安备 33010602011771号