[DS记录]P5066 [Ynoi2014] 人人本着正义之名
command_block
2021-06-29 11:36:22
**题意** : 维护一个长为 $n$ 的 `01`序列 $A$ ,有如下 $m$ 个操作:
- 把区间 $[l,r]$ 的数变成 $0$。
- 把区间 $[l,r]$ 的数变成 $1$。
- $[l,r-1]$ 内所有数 $a_i$,变为 $a_i$ 与 $a_{i+1}$ 按位或的值,这些数同时进行这个操作。
- $[l+1,r]$ 内所有数 $a_i$,变为 $a_i$ 与 $a_{i-1}$ 按位或的值,这些数同时进行这个操作。
- $[l,r-1]$ 内所有数 $a_i$,变为 $a_i$ 与 $a_{i+1}$ 按位与的值,这些数同时进行这个操作。
- $[l+1,r]$ 内所有数 $a_i$,变为 $a_i$ 与 $a_{i-1}$ 按位与的值,这些数同时进行这个操作。
- 查询区间 $[l,r]$ 的和。
强制在线,$n,m\leq 3\times 10^6$ ,时限$\texttt{8s}$ ,空限$\texttt{512M}$。
------------
不难发现,操作相当于“区间内的 $0/1$ 连续段向 左/右 扩展一位”.
用平衡树维护极长 $01$ 连续段的左端点,以及颜色。
当某个颜色扩展时,若存在长度为 $1$ 的另一种颜色的连续段,则需要将其删除,并将两侧的连续段合并。(需要特殊考虑边界情况)
若某棵子树中不存在删除事件,则可以打标记维护。标记有两种 :“颜色 $0/1$ 前扩, $1/0$ 后缩”。
维护 $1$ 段的个数,两类段的最短长度(若不存在则为 $+\infty$,用于判定是否有删除事件),以及和。
连续段的个数是 $O(n+m)$ 的,于是花费在删除事件上的额外复杂度可以保证。
实现中用 leafy-Tree 维护。复杂度 $O\big((n+m)\log n\big)$。
本质不难,细节真多。
一不小心拿了个最优解。
leafy-Tree 牛逼!
```cpp
#include<algorithm>
#include<cstring>
#include<cstdio>
#define ll long long
#define MaxN 3000500
using namespace std;
namespace io {
char buf[5005000],*p1=buf,*p2=buf,obuf[5005000],*O=obuf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,5000000,stdin),p1==p2)?EOF:*p1++)
int rd() {
int x=0;char ch=getchar();
while(ch<'0'||'9'<ch)ch=getchar();
while('0'<=ch&&ch<='9')x=x*10+(ch^48),ch=getchar();
return x;
}
void putc(char ch){*O++=ch;}
void print(ll x){if(x>9)print(x/10);*O++=x%10+'0';}
void flush(bool op=0){if (O-obuf>=5000000||op){fwrite(obuf,O-obuf,1,stdout);O=obuf;}}
}using namespace io;
const int INF=1000000000;
struct Node{
int l,r,s,c,tg[2],x[2],p;bool v;
// t[v] ′ú±í??é? v ?°à?£? !v ?òoó??
inline void ladd(int t0,int t1){
tg[0]+=t0;tg[1]+=t1;p-=(v==0) ? t0 : t1;
x[0]+=t0-t1;x[1]+=t1-t0;s+=c*(t1-t0);
}
}a[MaxN<<1];
int tot,rub[MaxN],top;
int cre(){
if (top){
int u=rub[top--];
memset(&a[u],0,sizeof(Node));
return u;
}return ++tot;
}
inline void Init(int l,int r,int v,Node &A)
{A.p=l;A.v=v;A.x[v]=r-l+1;A.x[!v]=INF;A.c=v;A.s=v*(r-l+1);}
inline void up(int u){
int l=a[u].l,r=a[u].r;
a[u].p=a[l].p;a[u].v=a[l].v;
a[u].c=a[l].c+a[r].c;
a[u].s=a[l].s+a[r].s;
a[u].x[0]=min(a[l].x[0],a[r].x[0]);
a[u].x[1]=min(a[l].x[1],a[r].x[1]);
}
inline void ladd(int u){
if (a[u].tg[0]||a[u].tg[1]){
a[a[u].l].ladd(a[u].tg[0],a[u].tg[1]);
a[a[u].r].ladd(a[u].tg[0],a[u].tg[1]);
a[u].tg[0]=a[u].tg[1]=0;
}
}
inline int merge(int l,int r){
int u=cre();a[u].l=l;a[u].r=r;
up(u);return u;
}
int sl[MaxN],sm[MaxN],sr[MaxN],tl,tm,tr;
int n,rt,wfl,wfr;
void spiltl(int u){
if (!a[u].l){sm[++tm]=u;return ;}
ladd(rub[++top]=u);
spiltl(a[u].l);sm[++tm]=a[u].r;
}
void spiltr(int u){
if (!a[u].r){sm[++tm]=u;return ;}
ladd(rub[++top]=u);
sm[++tm]=a[u].l;spiltr(a[u].r);
}
int flag;
void spilt(int l=1,int r=n,int u=rt)
{
if (r<wfl-1||(!a[u].l&&r<wfl)){sl[++tl]=u;return ;}
if (wfr+1<l||(!a[u].l&&wfr<l)){sr[++tr]=u;return ;}
if ((wfl<l&&r<wfr&&(flag==2||a[u].x[!flag]>1))||!a[u].l)
{sm[++tm]=u;return ;}
ladd(rub[++top]=u);int mid=a[a[u].r].p-1;
spilt(l,mid,a[u].l);spilt(mid+1,r,a[u].r);
}
int s[MaxN<<1];
void build()
{
int tn=0;
memcpy(s+1,sl+1,sizeof(int)*tl);tn=tl;
memcpy(s+tn+1,sm+1,sizeof(int)*tm);tn+=tm;
memcpy(s+tn+1,sr+1,sizeof(int)*tr);tn+=tr;
while(tn>1){
for (int i=2;i<=tn;i+=2)
s[i/2]=merge(s[i-1],s[i]);
if (tn&1)s[(tn+1)/2]=s[tn];
tn=(tn+1)/2;
}rt=s[1];tl=tm=tr=0;
}
int m,x[MaxN];
int main()
{
n=rd();m=rd();
for (int i=1;i<=n;i++)x[i]=rd();
x[n+1]=-1;
for (int i=1,p=1;i<=n;i++)
if (x[i]!=x[i+1]){
Init(p,i,x[i],a[sm[++tm]=cre()]);
p=i+1;
}
build();
#define fir sm[1]
#define las sm[tm]
for (int i=1,op,tn,last=0;i<=m;i++){
op=rd();wfl=rd()^last;wfr=rd()^last;
if (3<=op&&op<=6&&wfl==wfr)continue;
if (op==3||op==4)flag=1;
if (op==5||op==6)flag=0;
if (op<3||op>6)flag=2;
spilt();
if (op==1||op==2){
op--;
int vl=a[fir].v,l=a[fir].p
,vr=a[las].v,r=a[las].p+a[las].x[vr]-1;
for (int i=1;i<=tm;i++)rub[++top]=sm[i];tm=0;
if (vl!=op&&l<wfl)Init(l,wfl-1,vl,a[sm[++tm]=cre()]);
Init((vl==op) ? l : wfl,(vr==op) ? r : wfr,op,a[sm[++tm]=cre()]);
if (vr!=op&&wfr<r)Init(wfr+1,r,vr,a[sm[++tm]=cre()]);
}
if (3<=op&&op<=6){
memcpy(s+1,sm+1,sizeof(int)*tm);
tn=tm;tm=0;
for (int i=1;i<=tn;i++){
if (tm&&a[s[i]].x[!flag]==1)
spiltr(sm[tm--]);
if (tm&&a[sm[tm]].x[!flag]==1)
spiltl(s[i]);
else sm[++tm]=s[i];
}memcpy(s+1,sm+1,sizeof(int)*tm);
tn=tm;tm=0;
}
if (op==3||op==5){
bool fl=(a[s[tn]].v!=flag);if (fl)tn--;
if (tn&&a[s[1]].x[!flag]>1){
int u=sm[tm=1]=s[1];
if (a[u].v!=flag)a[u].ladd(flag==0,flag==1);
}
for (int i=2;i<=tn;i++)
if (a[s[i]].x[!flag]==1){
i++;
int l=a[sm[tm]].p,r=a[s[i]].p+a[s[i]].x[flag]-1;
rub[++top]=sm[tm--];rub[++top]=s[i];
Init(l,r,flag,a[sm[++tm]=cre()]);
}else a[sm[++tm]=s[i]].ladd(flag==0,flag==1);
if (fl)sm[++tm]=s[tn+1];
}
if (op==4||op==6){
reverse(s+1,s+tn+1);
bool fl=(a[s[tn]].v!=flag);if (fl)tn--;
if (tn&&a[s[1]].x[!flag]>1){
int u=sm[tm=1]=s[1];
if (a[u].v!=flag)a[u].ladd(-(flag==1),-(flag==0));
}
for (int i=2;i<=tn;i++)
if (a[s[i]].x[!flag]==1){
i++;
int l=a[s[i]].p,r=a[sm[tm]].p+a[sm[tm]].x[flag]-1;
rub[++top]=s[i];rub[++top]=sm[tm--];
Init(l,r,flag,a[sm[++tm]=cre()]);
}else a[sm[++tm]=s[i]].ladd(-(flag==1),-(flag==0));
if (fl)sm[++tm]=s[tn+1];
reverse(sm+1,sm+tm+1);
}
if (op==7){
int ans=0;
if (tm==1)ans=a[fir].v*(wfr-wfl+1);
else {
for (int i=2;i<tm;i++)ans+=a[sm[i]].s;
if (a[fir].v)ans+=a[fir].s-wfl+a[fir].p;
if (a[las].v)ans+=wfr-a[las].p+1;
}print(last=ans);putc('\n');flush();
}else {
if (tl&&a[sm[1]].p==wfl&&a[sl[tl]].v==a[sm[1]].v){
int v=a[sm[1]].v,l=a[sl[tl]].p,r=a[sm[1]].p+a[sm[1]].x[v]-1;
rub[++top]=sl[tl--];rub[++top]=sm[1];
Init(l,r,v,a[sm[1]=cre()]);
}
if (tr&&a[sr[1]].p==wfr+1&&a[sm[tm]].v==a[sr[1]].v){
int v=a[sr[1]].v,l=a[sm[tm]].p,r=a[sr[1]].p+a[sr[1]].x[v]-1;
rub[++top]=sm[tm--];rub[++top]=sr[1];
Init(l,r,v,a[sr[1]=cre()]);
}
}build();
}flush(1);
return 0;
}
```