数据结构杂题乱记
由于是杂题乱记所以题目大多数不会太难。
P2572 [SCOI2010] 序列操作
题目内容
给你一个 \(01\) 序列,支持 \(5\) 种操作:
0 l r
区间赋值为 \(0\);1 l r
区间赋值为 \(1\);2 l r
区间取反,即 \(0\) 变 \(1\)、\(1\) 变 \(0\);3 l r
询问区间 \(1\) 总数。4 l r
询问区间最长 \(1\) 连续段长度。
思路
看到区间赋值,珂朵莉树板子题,然后翻看讨论区,发现珂朵莉树被Hack了,于是老老实实打线段树。同色连续段问题,对于每个节点开一个三元组,表示区间最长连续段长度,以区间左端点为左边界的最长连续段长度,以区间右端点为右边界的最长连续段长度。合并直接做即可。由于有区间翻转,所以再保存一个 \(0\) 的连续段三元组,更新时直接把 \(0,1\) 的三元组交换即可。注意如果左区间颜色完全一致,则父亲区间的左端点最长连续段长度为左区间的整体长度+右区间的左端点最长连续段长度。然后对于三个修改操作,分别记它们的 \(lazy\) 标记为 \(lazy0,lazy1,lazy2\),则有:
-
如果当前操作为 \(0\) 或 \(1\),则清空其余标记然后赋值。
-
如果当前操作为 \(2\) 且该区间有 \(0\) 标记,删除 \(0\) 标记改为 \(1\) 标记,进行相应的赋值,不加 \(2\) 标记;有 \(1\) 标记同理。
-
如果当前操作为 \(2\) 且该区间没有 \(0\) 或 \(1\) 标记,则进行交换操作,然后对 \(2\) 标记取反,即无变为有、有变为无。
容易发现这样操作一个节点最多只会同时带有 \(1\) 种标记。无论是更新时的加标记还是pushdown都这么做就对了。然后这题就比较平凡了。为了直观,我把所有东西都分开写了,也许会有更简便的写法。
代码
#include<bits/stdc++.h>
using namespace std;
#define il inline
#define ri register int
#define inf 0x3f3f3f3f
int a,b,c[100001],u,v,w;
struct node
{
int lid,rid,val;
bool can;
node operator +(const node &A)
{
register node rn;
rn.val=max((*this).val,A.val);
rn.val=max(rn.val,(*this).rid+A.lid);
if((*this).can)
{
rn.lid=(*this).lid+A.lid;
}
else
{
rn.lid=(*this).lid;
}
if(A.can)
{
rn.rid=(*this).rid+A.rid;
}
else
{
rn.rid=A.rid;
}
rn.can=(*this).can&A.can;
return rn;
}
};
struct Segment_Tree
{
#define N 400004
int left[N],right[N],num2[N];
bool lazy0[N],lazy1[N],lazy2[N];
node num0[N],num1[N];
il int ls(int x)
{
return x<<1;
}
il int rs(int x)
{
return x<<1|1;
}
il void pushup(int x)
{
num0[x]=num0[ls(x)]+num0[rs(x)];
num1[x]=num1[ls(x)]+num1[rs(x)];
num2[x]=num2[ls(x)]+num2[rs(x)];
}
il void pushdown(int x)
{
if(lazy0[x])
{
lazy0[x]=false;
lazy1[ls(x)]=lazy2[ls(x)]=lazy1[rs(x)]=lazy2[rs(x)]=false;
lazy0[ls(x)]=lazy0[rs(x)]=true;
ri len=right[ls(x)]-left[ls(x)]+1;
num0[ls(x)]={len,len,len,true};
num1[ls(x)]={0,0,0,false};
num2[ls(x)]=0;
len=right[rs(x)]-left[rs(x)]+1;
num0[rs(x)]={len,len,len,true};
num1[rs(x)]={0,0,0,false};
num2[rs(x)]=0;
}
if(lazy1[x])
{
lazy1[x]=false;
lazy0[ls(x)]=lazy2[ls(x)]=lazy0[rs(x)]=lazy2[rs(x)]=false;
lazy1[ls(x)]=lazy1[rs(x)]=true;
ri len=right[ls(x)]-left[ls(x)]+1;
num0[ls(x)]={0,0,0,false};
num1[ls(x)]={len,len,len,true};
num2[ls(x)]=len;
len=right[rs(x)]-left[rs(x)]+1;
num0[rs(x)]={0,0,0,false};
num1[rs(x)]={len,len,len,true};
num2[rs(x)]=len;
}
if(lazy2[x])
{
lazy2[x]=false;
ri len=right[ls(x)]-left[ls(x)]+1;
if(lazy0[ls(x)]||lazy1[ls(x)])
{
swap(lazy0[ls(x)],lazy1[ls(x)]);
if(lazy0[ls(x)])
{
num0[ls(x)]={len,len,len,true};
num1[ls(x)]={0,0,0,false};
num2[ls(x)]=0;
}
else
{
num0[ls(x)]={0,0,0,false};
num1[ls(x)]={len,len,len,true};
num2[ls(x)]=len;
}
}
else
{
num2[ls(x)]=len-num2[ls(x)];
swap(num1[ls(x)],num0[ls(x)]);
lazy2[ls(x)]^=1;
}
len=right[rs(x)]-left[rs(x)]+1;
if(lazy0[rs(x)]||lazy1[rs(x)])
{
swap(lazy0[rs(x)],lazy1[rs(x)]);
if(lazy0[rs(x)])
{
num0[rs(x)]={len,len,len,true};
num1[rs(x)]={0,0,0,false};
num2[rs(x)]=0;
}
else
{
num0[rs(x)]={0,0,0,false};
num1[rs(x)]={len,len,len,true};
num2[rs(x)]=len;
}
}
else
{
num2[rs(x)]=len-num2[rs(x)];
swap(num1[rs(x)],num0[rs(x)]);
lazy2[rs(x)]^=1;
}
}
}
void build(int x,int lt,int rt)
{
left[x]=lt;
right[x]=rt;
if(left[x]==right[x])
{
if(c[lt])
{
num2[x]=1;
num1[x]={1,1,1,true};
}
else
{
num0[x]={1,1,1,true};
}
return;
}
ri me=(lt+rt)>>1;
build(ls(x),lt,me);
build(rs(x),me+1,rt);
pushup(x);
}
void add0(int x,int lt,int rt)
{
if(lt<=left[x]&&right[x]<=rt)
{
lazy1[x]=lazy2[x]=false;
lazy0[x]=true;
ri len=right[x]-left[x]+1;
num0[x]={len,len,len,true};
num1[x]={0,0,0,false};
num2[x]=0;
return;
}
pushdown(x);
ri me=(left[x]+right[x])>>1;
if(lt<=me)
{
add0(ls(x),lt,rt);
}
if(rt>me)
{
add0(rs(x),lt,rt);
}
pushup(x);
}
void add1(int x,int lt,int rt)
{
if(lt<=left[x]&&right[x]<=rt)
{
lazy0[x]=lazy2[x]=false;
lazy1[x]=true;
ri len=right[x]-left[x]+1;
num0[x]={0,0,0,false};
num1[x]={len,len,len,true};
num2[x]=len;
return;
}
pushdown(x);
ri me=(left[x]+right[x])>>1;
if(lt<=me)
{
add1(ls(x),lt,rt);
}
if(rt>me)
{
add1(rs(x),lt,rt);
}
pushup(x);
}
void add2(int x,int lt,int rt)
{
if(lt<=left[x]&&right[x]<=rt)
{
ri len=right[x]-left[x]+1;
if(lazy0[x]||lazy1[x])
{
swap(lazy0[x],lazy1[x]);
if(lazy0[x])
{
num0[x]={len,len,len,true};
num1[x]={0,0,0,false};
num2[x]=0;
}
else
{
num0[x]={0,0,0,false};
num1[x]={len,len,len,true};
num2[x]=len;
}
}
else
{
num2[x]=len-num2[x];
swap(num1[x],num0[x]);
lazy2[x]^=1;
}
return;
}
pushdown(x);
ri me=(left[x]+right[x])>>1;
if(lt<=me)
{
add2(ls(x),lt,rt);
}
if(rt>me)
{
add2(rs(x),lt,rt);
}
pushup(x);
}
int find1(int x,int lt,int rt)
{
if(lt<=left[x]&&right[x]<=rt)
{
return num2[x];
}
pushdown(x);
ri me=(left[x]+right[x])>>1,rn=0;
if(lt<=me)
{
rn+=find1(ls(x),lt,rt);
}
if(rt>me)
{
rn+=find1(rs(x),lt,rt);
}
return rn;
}
node find2(int x,int lt,int rt)
{
if(lt<=left[x]&&right[x]<=rt)
{
return num1[x];
}
pushdown(x);
ri me=(left[x]+right[x])>>1;
register node rn1={-1,-1,-1},rn2={-1,-1,-1};
if(lt<=me)
{
rn1=find2(ls(x),lt,rt);
}
if(rt>me)
{
rn2=find2(rs(x),lt,rt);
}
if(rn1.val>=0&&rn2.val>=0)
{
return rn1+rn2;
}
else
{
if(rn1.val>=0)
{
return rn1;
}
else
{
return rn2;
}
}
}
#undef N
}st;
int main()
{
scanf("%d%d",&a,&b);
for(ri i=1;i<=a;i++)
{
scanf("%d",&c[i]);
}
st.build(1,1,a);
while(b--)
{
scanf("%d%d%d",&u,&v,&w);
v++;
w++;
switch(u)
{
case 0:
{
st.add0(1,v,w);
break;
}
case 1:
{
st.add1(1,v,w);
break;
}
case 2:
{
st.add2(1,v,w);
break;
}
case 3:
{
printf("%d\n",st.find1(1,v,w));
break;
}
case 4:
{
printf("%d\n",st.find2(1,v,w).val);
break;
}
}
}
return 0;
}