@xiaoziyao
2021-08-19T12:27:48.000000Z
字数 7296
阅读 879
解题报告
P7825 「RdOI R3」VSQ解题报告:
给定一个长度为 的 01 序列,共 次操作,每次支持区间推平,区间反转,查询区间最长 间隔串,查询区间长度为 的 间隔串数量。
。
为什么我要做这种毒瘤 ds 题啊,毒瘤 ds 毁我一上午。
首先套路地进行差分,那么我们要进行的操作就变成了:支持序列 的区间推平,异或,支持 的差分序列 的区间推平为 和单点修改,以及查询 的区间最长全 段和区间长度大于等于 的全 段数。
除了最后一个操作都可以用两颗线段树套路地维护,考虑最后一个操作怎么维护,考场我想的是分块,发现复杂度完全不能接受,于是写了写珂朵莉树,发现也不行,就罚坐到比赛结束。/ll
实际上可以考虑用第二棵线段树同时维护每个线段树区间的所有全 段,每次区间推平为 就在每个结点暴力删除全 段,单点修改就在对应的结点用珂朵莉树类似的写法合并与分裂区间,然后每个区间的长度扔到对应结点的树状数组里,每次查询记一下上个位置,然后在树状数组内查一查,分类讨论一下就可以做了。
时间复杂度:。
#include<stdio.h>
#include<math.h>
#include<vector>
#include<set>
#define lc(x) (x)<<1
#define rc(x) (x)<<1|1
#define lowbit(x) x&-x
using namespace std;
const int maxn=500005,maxm=500005,maxt=maxn<<2;
int n,m;
int a[maxn],b[maxn],qo[maxm],ql[maxm],qr[maxm],qk[maxm],tag[maxt],lazy[maxt];
void abuild(int l,int r,int now){
lazy[now]=-1;
if(l==r){
lazy[now]=a[l];
return ;
}
int mid=(l+r)>>1;
abuild(l,mid,lc(now)),abuild(mid+1,r,rc(now));
}
inline void agetlazy(int now,int v){
lazy[now]=v,tag[now]=0;
}
inline void agettag(int now){
if(lazy[now]!=-1)
lazy[now]^=1;
else tag[now]^=1;
}
inline void apushdown(int now){
if(tag[now])
agettag(lc(now)),agettag(rc(now)),tag[now]=0;
if(lazy[now]!=-1)
agetlazy(lc(now),lazy[now]),agetlazy(rc(now),lazy[now]),lazy[now]=-1;
}
void aupdate(int l,int r,int now,int L,int R,int v){
if(L<=l&&r<=R){
agetlazy(now,v);
return ;
}
int mid=(l+r)>>1;
apushdown(now);
if(L<=mid)
aupdate(l,mid,lc(now),L,R,v);
if(mid<R)
aupdate(mid+1,r,rc(now),L,R,v);
}
void aupdatexor(int l,int r,int now,int L,int R){
if(L<=l&&r<=R){
agettag(now);
return ;
}
int mid=(l+r)>>1;
apushdown(now);
if(L<=mid)
aupdatexor(l,mid,lc(now),L,R);
if(mid<R)
aupdatexor(mid+1,r,rc(now),L,R);
}
int aquery(int l,int r,int now,int pos){
if(l==r)
return tag[now]^lazy[now];
apushdown(now);
int mid=(l+r)>>1;
return pos<=mid? aquery(l,mid,lc(now),pos):aquery(mid+1,r,rc(now),pos);
}
vector<int>t1[maxt],t2[maxt];
void update(int now,int pos,int val){
if(pos==1)
return ;
int len=t1[now].size()-1;
for(int i=len-pos+1;i<=len;i+=lowbit(i))
t1[now][i]+=val,t2[now][i]+=val*pos;
}
int query(int now,int pos){
if(pos==1)
return 0;
int len=t1[now].size()-1,res=0;
if(len<pos)
return 0;
for(int i=len-pos+1;i;i-=lowbit(i))
res+=t2[now][i]-t1[now][i]*(pos-1);
return res;
}
int blazy[maxt];
struct bnode{
int pre,suf,maxx,len;
}t[maxt];
struct section{
int l,r;
bool operator < (const section &p)const{
return l<p.l;
}
}lst;
set<section>s[maxt];
void cmodify(int now,int x,int v){
// printf("cmodify %d (%d,%d)\n",now,x,v);
if(v==1){
if(s[now].empty()){
s[now].insert(section{x,x}),update(now,1,1);
return ;
}
set<section>::iterator itr=s[now].upper_bound(section{x,-1}),itl=itr;
itl--;
int l=itl->l,r=itr->r;
int lt=itr!=s[now].begin()&&itl->r==x-1,rt=itr!=s[now].end()&&itr->l==x+1;
if(lt==0&&rt==0)
s[now].insert(section{x,x}),update(now,1,1);
if(lt==1&&rt==0)
s[now].erase(itl),update(now,x-l,-1),s[now].insert(section{l,x}),update(now,x-l+1,1);
if(lt==0&&rt==1)
s[now].erase(itr),update(now,r-x,-1),s[now].insert(section{x,r}),update(now,r-x+1,1);
if(lt==1&&rt==1)
s[now].erase(itl),update(now,x-l,-1),s[now].erase(itr),update(now,r-x,-1),s[now].insert(section{l,r}),update(now,r-l+1,1);
}
if(v==0){
set<section>::iterator it=s[now].upper_bound(section{x,-1});
it--;
int l=it->l,r=it->r;
s[now].erase(it),update(now,r-l+1,-1);
if(l==x&&r!=x)
s[now].insert(section{l+1,r}),update(now,r-l,1);
if(l!=x&&r==x)
s[now].insert(section{l,r-1}),update(now,r-l,1);
if(l!=x&&r!=x)
s[now].insert(section{l,x-1}),update(now,x-l,1),s[now].insert(section{x+1,r}),update(now,r-x,1);
}
}
set<section>::iterator split(int now,int pos){
set<section>::iterator it=s[now].lower_bound(section{pos,-1}),tmp=it;
if(it!=s[now].end()&&(it==s[now].begin()||it->l==pos))
return it;
tmp--;
if(tmp->r<pos)
return it;
int l=tmp->l,r=tmp->r;
s[now].erase(tmp),update(now,r-l+1,-1);
if(pos>l)
s[now].insert(section{l,pos-1}),update(now,pos-l,1);
update(now,r-pos+1,1);
return s[now].insert(section{pos,r}).first;
}
bnode merge(bnode a,bnode b){
bnode res;
res.pre=a.len==a.pre? (a.len+b.pre):a.pre;
res.suf=b.len==b.suf? (b.len+a.suf):b.suf;
res.maxx=max(max(a.maxx,b.maxx),a.suf+b.pre);
res.len=a.len+b.len;
return res;
}
inline void bpushup(int now){
t[now]=merge(t[lc(now)],t[rc(now)]);
}
void bbuild(int l,int r,int now){
// printf("l=%d r=%d now=%d\n",l,r,now);
t1[now].resize(r-l+2),t2[now].resize(r-l+2);
for(int i=l;i<=r;i++)
if(b[i])
cmodify(now,i,1);
if(l==r){
t[now].len=1,t[now].pre=t[now].suf=t[now].maxx=b[l];
return ;
}
int mid=(l+r)>>1;
bbuild(l,mid,lc(now)),bbuild(mid+1,r,rc(now));
bpushup(now);
}
inline void bgetlazy(int now){
t[now].pre=t[now].suf=t[now].maxx=0,blazy[now]=1;
}
inline void bpushdown(int now){
if(blazy[now])
bgetlazy(lc(now)),bgetlazy(rc(now)),blazy[now]=0;
}
void bmodify(int l,int r,int now,int pos,int v){
cmodify(now,pos,v);
if(l==r){
b[l]=t[now].pre=t[now].suf=t[now].maxx=v;
return ;
}
int mid=(l+r)>>1;
bpushdown(now);
if(pos<=mid)
bmodify(l,mid,lc(now),pos,v);
else bmodify(mid+1,r,rc(now),pos,v);
bpushup(now);
}
void bupdate(int l,int r,int now,int L,int R){
if(L<=l&&r<=R){
bgetlazy(now);
return ;
}
int mid=(l+r)>>1;
bpushdown(now);
if(L<=mid)
bupdate(l,mid,lc(now),L,R);
if(mid<R)
bupdate(mid+1,r,rc(now),L,R);
bpushup(now);
}
void cupdate(int l,int r,int now,int L,int R){
if(s[now].size()==0)
return ;
if(l==r){
for(set<section>::iterator it=s[now].begin();it!=s[now].end();it=s[now].erase(it))
update(now,it->r-it->l+1,-1);
return ;
}
set<section>::iterator itr=split(now,min(r,R)+1),itl=split(now,max(l,L));
while(itl!=itr)
update(now,itl->r-itl->l+1,-1),itl=s[now].erase(itl);
int mid=(l+r)>>1;
if(L<=mid)
cupdate(l,mid,lc(now),L,R);
if(mid<R)
cupdate(mid+1,r,rc(now),L,R);
}
int bget(int l,int r,int now,int pos){
if(l==r)
return t[now].maxx;
int mid=(l+r)>>1;
bpushdown(now);
return pos<=mid? bget(l,mid,lc(now),pos):bget(mid+1,r,rc(now),pos);
}
int bquerysum(int l,int r,int now,int L,int R,int K){
if(s[now].empty())
return 0;
if(L<=l&&r<=R){
int res=query(now,K);
section st=*s[now].begin(),ed=*s[now].rbegin();
if(lst.r+1==st.l){
res+=max(st.r-lst.l+1-K+1,0)-max(lst.r-lst.l+1-K+1,0)-max(st.r-st.l+1-K+1,0);
if(s[now].size()==1)
lst=section{lst.l,ed.r};
else lst=ed;
}
else lst=ed;
return res;
}
int mid=(l+r)>>1,res=0;
if(L<=mid)
res+=bquerysum(l,mid,lc(now),L,R,K);
if(mid<R)
res+=bquerysum(mid+1,r,rc(now),L,R,K);
return res;
}
bnode bquerymax(int l,int r,int now,int L,int R){
if(L<=l&&r<=R)
return t[now];
int mid=(l+r)>>1;
bpushdown(now);
if(L<=mid&&mid<R)
return merge(bquerymax(l,mid,lc(now),L,R),bquerymax(mid+1,r,rc(now),L,R));
if(L<=mid)
return bquerymax(l,mid,lc(now),L,R);
return bquerymax(mid+1,r,rc(now),L,R);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
abuild(1,n,1);
for(int i=1;i<n;i++)
b[i]=a[i]^a[i+1];
bbuild(1,n,1);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&qo[i],&ql[i],&qr[i]);
if(qo[i]==3)
scanf("%d",&qk[i]);
}
for(int i=1;i<=m;i++){
int opt=qo[i],l=ql[i],r=qr[i],k=qk[i];
if(opt==0){
if(l>1){
int x=aquery(1,n,1,l-1);
if(bget(1,n,1,l-1)!=x)
bmodify(1,n,1,l-1,x);
}
if(r<n){
int y=aquery(1,n,1,r+1);
if(bget(1,n,1,r)!=y)
bmodify(1,n,1,r,y);
}
if(l<r)
bupdate(1,n,1,l,r-1),cupdate(1,n,1,l,r-1);
aupdate(1,n,1,l,r,0);
}
if(opt==1){
if(l>1){
int x=aquery(1,n,1,l-1)^1;
if(bget(1,n,1,l-1)!=x)
bmodify(1,n,1,l-1,x);
}
if(r<n){
int y=aquery(1,n,1,r+1)^1;
if(bget(1,n,1,r)!=y)
bmodify(1,n,1,r,y);
}
if(l<r)
bupdate(1,n,1,l,r-1),cupdate(1,n,1,l,r-1);
aupdate(1,n,1,l,r,1);
}
if(opt==2){
int x=bget(1,n,1,l-1),y=bget(1,n,1,r);
if(l>1)
bmodify(1,n,1,l-1,bget(1,n,1,l-1)^1);
if(r<n)
bmodify(1,n,1,r,bget(1,n,1,r)^1);
aupdatexor(1,n,1,l,r);
}
if(opt==3){
if(l==r)
puts("0");
else lst=section{-1,-1},printf("%d\n",bquerysum(1,n,1,l,r-1,k-1));
}
if(opt==4){
if(l==r)
puts("1");
else printf("%d\n",bquerymax(1,n,1,l,r-1).maxx+1);
}
}
return 0;
}