题解 P2572 【[SCOI2010]序列操作】

· · 题解

线段树??

不要!!

fhq \ Treap 是也!!

线段树维护区间最长连续1很麻烦,平衡树就能很好地减少码量

有一个减少码量的神器:结构体内定义函数!(就是封装起来)

在外部直接疯狂调用即可!

虽说比较慢,但AC是没问题的,这又是省选题,开O2后快到飞起!

细节各位大佬都已说了,这里再点一下:

首先是反转和推平操作的优先级问题,其实谁先谁后都行,但都要注意前一个操作会影响后一个操作

比如我写的是先反转再推平,那么反转操作时别忘了也把推平标记取反

平衡树节点记录信息既要记录关于0的也要记录关于1的,这样子反转操作直接把有关0,1的swap一下即可

说一下变量含义,方便大家理解:

$rmax[0/1]$ 区间最右侧连续0/1的个数 $mx[0/1]$ 区间内最多有连续的0/1的个数 $sum1$ 区间内1的个数 $rev$ 反转标记 $cov$ 推平标记(若值为-1则表示不用推平) $key$ 键值 $val$ 这个位置的值(0/1) $siz$ 子树(区间)大小 $ch[0/1]$ 左/右儿子 结构体里的封装(只用封装反转和推平) ```cpp struct node{ int siz,key,ch[2],val,lmax[2],rmax[2],mx[2],sum1; int cov; bool rev; inline void Rev(){//反转 rev^=1; swap(lmax[0],lmax[1]); swap(rmax[0],rmax[1]); swap(mx[0],mx[1]); if(cov!=-1)cov^=1; sum1=siz-sum1; val^=1; } inline void Cov(int d){//推平 val=d; cov=d; sum1=(d?siz:0); for(int i=0;i<=1;i++){ lmax[i]=rmax[i]=mx[i]=((d==i)?siz:0); } } }t[N]; ``` 这样就能保证代码的简洁啦!o(* ̄▽ ̄\*)ブ 没有一点压行,长度比除珂朵莉树外的题解短多了 ```cpp #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> using namespace std; #define N 100100 inline int read(){ int x=0,f=1; char c=getchar(); while(c<'0'||c>'9'){ if(c=='-')f=-1; c=getchar(); } while(c>='0'&&c<='9'){ x=(x<<3)+(x<<1)+c-'0'; c=getchar(); } return x*f; } int n,m,cnt,root; struct node{ int siz,key,ch[2],val,lmax[2],rmax[2],mx[2],sum1; int cov; bool rev; inline void Rev(){ rev^=1; swap(lmax[0],lmax[1]); swap(rmax[0],rmax[1]); swap(mx[0],mx[1]); if(cov!=-1)cov^=1; sum1=siz-sum1; val^=1; } inline void Cov(int d){ val=d; cov=d; sum1=(d?siz:0); for(int i=0;i<=1;i++){ lmax[i]=rmax[i]=mx[i]=((d==i)?siz:0); } } }t[N]; int NewNode(int data){//初始化别漏了东西,否则会出一些奇怪的错误 int k=++cnt; t[k].val=t[k].sum1=data; t[k].siz=1; t[k].key=rand(); t[k].ch[0]=t[k].ch[1]=0; t[k].rev=0; t[k].cov=-1; for(int i=0;i<=1;i++){ t[k].lmax[i]=t[k].rmax[i]=t[k].mx[i]=(data==i); } return k; } inline void update(int k){ t[k].siz=t[t[k].ch[0]].siz+t[t[k].ch[1]].siz+1; t[k].sum1=t[t[k].ch[0]].sum1+t[t[k].ch[1]].sum1+t[k].val; for(int i=0;i<=1;i++){ t[k].lmax[i]=t[t[k].ch[0]].lmax[i]; t[k].rmax[i]=t[t[k].ch[1]].rmax[i]; t[k].mx[i]=max(t[t[k].ch[0]].mx[i],t[t[k].ch[1]].mx[i]); if(t[k].val==i){//当i等于节点的值时还要再次更新 if(t[t[k].ch[0]].sum1==(i?t[t[k].ch[0]].siz:0)){//判断是否左子树内都是相同的值(并且等于i) t[k].lmax[i]+=1+t[t[k].ch[1]].lmax[i]; } if(t[t[k].ch[1]].sum1==(i?t[t[k].ch[1]].siz:0)){//类上 t[k].rmax[i]+=1+t[t[k].ch[0]].rmax[i]; } t[k].mx[i]=max(t[k].mx[i],t[t[k].ch[0]].rmax[i]+1+t[t[k].ch[1]].lmax[i]); } } } inline void pushdown(int k){ if(t[k].rev){ t[t[k].ch[0]].Rev(); t[t[k].ch[1]].Rev(); t[k].rev=0; } if(t[k].cov!=-1){ t[t[k].ch[0]].Cov(t[k].cov); t[t[k].ch[1]].Cov(t[k].cov); t[k].cov=-1; } } int Merge(int l,int r){ if(!l||!r){ return l+r; } pushdown(l),pushdown(r); if(t[l].key<t[r].key){ t[l].ch[1]=Merge(t[l].ch[1],r); update(l); return l; } else{ t[r].ch[0]=Merge(l,t[r].ch[0]); update(r); return r; } } void Split(int k,int data,int &l,int &r){ if(!k){ l=r=0; return ; } pushdown(k); if(t[t[k].ch[0]].siz+1<=data){ l=k; Split(t[k].ch[1],data-t[t[k].ch[0]].siz-1,t[k].ch[1],r); } else{ r=k; Split(t[k].ch[0],data,l,t[k].ch[0]); } update(k); } inline void Change(int x,int y,int d){ int l,p,r; Split(root,y,l,r); Split(l,x-1,l,p); t[p].Cov(d); root=Merge(Merge(l,p),r); } inline void Reverse(int x,int y){ int l,p,r; Split(root,y,l,r); Split(l,x-1,l,p); t[p].Rev(); root=Merge(Merge(l,p),r); } inline int Count1(int x,int y){ int l,p,r; Split(root,y,l,r); Split(l,x-1,l,p); int ans=t[p].sum1; root=Merge(Merge(l,p),r); return ans; } inline int Ask_MX(int x,int y){ int l,p,r; Split(root,y,l,r); Split(l,x-1,l,p); int ans=t[p].mx[1]; root=Merge(Merge(l,p),r); return ans; } int main(){ n=read(),m=read(); for(register int i=1;i<=n;++i){ int x=read(); root=Merge(root,NewNode(x)); } for(register int i=1;i<=m;++i){ int opt=read(),l=read()+1,r=read()+1; if(opt==0){ Change(l,r,0); } else if(opt==1){ Change(l,r,1); } else if(opt==2){ Reverse(l,r); } else if(opt==3){ printf("%d\n",Count1(l,r)); } else{ printf("%d\n",Ask_MX(l,r)); } } return 0; } ``` [*Froggy's blog*](https://www.luogu.org/blog/1445353309froggy/) #### 呱!!