多校第十二場 題解
阿新 • • 發佈:2020-07-25
A. string
對於這類字串匹配題,有個套路是直接用 \(FFT\) 優化。
然後發現這題字符集很小,所以列舉一個字元,將匹配串中的這個字元設為 \(1\),模式串中的非這個字元設為 \(1\)。
然後用一些技巧優化一下,就可以用 \(|\sum|+1\) 次長度為 \(n\) 的 \(DFT\) 求出答案了。
B. Tree
容易發現這題就是通過與 \(LCT\) 類似的樹構造出深度和最大的原樹。
若一個節點在實鏈上,我們只關注每個深度的當前最大值。
若一個節點上面是虛邊,我們只需要這個節點作為 \(splay\) 根節點的當前最大值。
所以可以設計一個 \(dp\), \(dp_{i,j}\)
\(f_i=\max \limits_{j=1}^{sz_i}dp_{i,j}\) 這個玩意表示若 \(i\) 為虛子樹的最大值。
發現轉移主要與左子樹有關,因為左子樹貢獻了一些深度。
所以列舉左子樹是誰,列舉左子樹的大小就行了。
C. sort
如果只有排序操作,一個方法是這樣的。
開一個平衡樹維護已經排好序的每個連續段。
對於每個連續段,用 平衡樹/\(01trie\) 等來實現分裂,暴力去合併複雜度就是對的。
拓展到本題上,仍然使用平衡樹套 \(01trie\)。
在平衡樹上打標記,表示對子樹內所有 \(01trie\)
在 \(01trie\) 上也打標記,表示對子樹內節點進行這種操作。
可以認為,平衡樹上的標記是上次排序到這次排序之間的,也就是說不影響相對關係的。
而 \(01trie\) 上的標記是上次排序之前的,也就是說影響相對關係。
所以當 \(01trie\) 上標記下傳的時候,需要交換兩個兒子或者合併兩個兒子。
對於修改操作,只需要在區間的平衡樹上打個標記。
對於排序操作,可以暴力拉出來每個連續段,把它上面的標記打在 \(01trie\) 上,併合並在一起。
思路大概就是這樣,打起來有點噁心。
#include<bits/stdc++.h> using namespace std; const int N=1e5+7; int n,m; int a[N]; struct Tag{ int A,B,C; Tag():A(-1),B(0),C(0){} inline friend void operator *= (Tag &a,const Tag &b){ a.A&=b.A; a.B&=b.A; a.C&=b.A; a.B|=b.B; a.C&=-1^b.B; a.C^=b.C; } inline int mp(int k,int f){ return ((f&(A>>k&1))|(B>>k&1))^(C>>k&1); } }; namespace Trie{ int cnt; int ch[N*180][2],sz[N*180]; Tag lzy[N*180]; inline void down(int p); inline int merge(int x,int y,int dep); inline void insert(int p,int x){ for(int i=31;~i;--i){ if(!ch[p][x>>i&1]) ch[p][x>>i&1]=++cnt; ++sz[p]; p=ch[p][x>>i&1]; } ++sz[p]; } inline void update(int p){ sz[p]=sz[ch[p][0]]+sz[ch[p][1]]; } inline void down(int p,int dep){ lzy[ch[p][0]]*=lzy[p]; lzy[ch[p][1]]*=lzy[p]; if(lzy[p].mp(dep-1,0)==1&&lzy[p].mp(dep-1,1)==0) swap(ch[p][0],ch[p][1]); else if(lzy[p].mp(dep-1,0)==0&&lzy[p].mp(dep-1,1)==0) ch[p][0]=merge(ch[p][0],ch[p][1],dep-1),ch[p][1]=0; else if(lzy[p].mp(dep-1,0)==1&&lzy[p].mp(dep-1,1)==1) ch[p][1]=merge(ch[p][0],ch[p][1],dep-1),ch[p][0]=0; lzy[p]=Tag(); } inline int merge(int x,int y,int dep){ if(!x||!y) return x|y; sz[x]+=sz[y]; if(!dep) return x; down(x,dep); down(y,dep); ch[x][0]=merge(ch[x][0],ch[y][0],dep-1); ch[x][1]=merge(ch[x][1],ch[y][1],dep-1); return update(x),x; } inline void split(int p,int k,int dep,int &x,int &y){ if(!dep) return x=++cnt,y=++cnt,sz[x]=k,sz[y]=sz[p]-k,void(); down(p,dep); x=++cnt; y=++cnt; if(sz[ch[p][0]]>=k) split(ch[p][0],k,dep-1,ch[x][0],ch[y][0]),ch[y][1]=ch[p][1],update(x),update(y); else split(ch[p][1],k-sz[ch[p][0]],dep-1,ch[x][1],ch[y][1]),ch[x][0]=ch[p][0],update(x),update(y); } void dfs(int x,int dep,int ret,Tag now){ if(!dep){ int ans=0; for(int i=0;i<32;++i) ans|=now.mp(i,ret>>i&1)<<i; for(int i=0;i<sz[x];++i) printf("%u ",ans); return ; } down(x,dep); if(ch[x][0]) dfs(ch[x][0],dep-1,ret,now); if(ch[x][1]) dfs(ch[x][1],dep-1,ret|(1<<dep-1),now); } } namespace Treap{ int rt,cnt; int ch[N*15][2],sz[N*15],rnd[N*15],l[N*15],r[N*15],tr[N*15]; Tag val[N*15],lzy[N*15]; inline void update(int p){ sz[p]=1+sz[ch[p][0]]+sz[ch[p][1]]; } inline void down(int p){ val[ch[p][0]]*=lzy[p]; val[ch[p][1]]*=lzy[p]; lzy[ch[p][0]]*=lzy[p]; lzy[ch[p][1]]*=lzy[p]; lzy[p]=Tag(); } inline void split(int p,int k,int &x,int &y){ if(!p) return x=y=0,void(); down(p); if(sz[ch[p][0]]>=k) split(ch[p][0],k,x,ch[p][0]),y=p,update(p); else split(ch[p][1],k-sz[ch[p][0]]-1,ch[p][1],y),x=p,update(p); } inline int merge(int x,int y){ if(!x||!y) return x|y; if(rnd[x]>rnd[y]) return down(x),ch[x][1]=merge(ch[x][1],y),update(x),x; else return down(y),ch[y][0]=merge(x,ch[y][0]),update(y),y; } inline int Rank(int p,int k,int ret=0){ while(p){ down(p); if(r[p]<=k) ret+=sz[ch[p][0]]+1,p=ch[p][1]; else p=ch[p][0]; } return ret; } inline void cut(int k){ int a,b; split(rt,Rank(rt,k),rt,a); if(!a) return ; split(a,1,a,b); if(l[a]==k+1) return rt=merge(rt,merge(a,b)),void(); int c=++cnt,d=++cnt,num=k-l[a]+1; val[c]=val[d]=val[a]; sz[c]=sz[d]=1; rnd[c]=rand(); rnd[d]=rand(); Trie::split(tr[a],num,32,tr[c],tr[d]); l[c]=l[a]; r[c]=k; l[d]=k+1; r[d]=r[a]; rt=merge(rt,merge(merge(c,d),b)); } inline void Split(int L,int R,int &a,int &b,int &c){ cut(L-1); cut(R); split(rt,Rank(rt,L-1),a,b); split(b,Rank(b,R),b,c); } void dfs(int x,int h){ down(x); Trie::lzy[tr[x]]*=val[x]; tr[h]=Trie::merge(tr[h],tr[x],32); if(ch[x][0]) dfs(ch[x][0],h); if(ch[x][1]) dfs(ch[x][1],h); } } inline int read(register int x=0,register char ch=getchar()){ for(;!isdigit(ch);ch=getchar()) ; for(; isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+(ch^48); return x; } int main(){ freopen("sort.in","r",stdin); freopen("sort.out","w",stdout); n=read(); m=read(); for(int i=1;i<=n;++i){ a[i]=read(); ++Treap::cnt; Treap::l[i]=i; Treap::r[i]=i; Treap::sz[i]=1; Treap::rnd[i]=rand(); Treap::tr[i]=++Trie::cnt; Trie::insert(Treap::tr[i],a[i]); Treap::rt=Treap::merge(Treap::rt,i); } for(int i=1,opt,l,r,x;i<=m;++i){ opt=read(); l=read(); r=read(); if(opt==1){ x=read(); int a,b,c; Tag now=Tag(); Treap::Split(l,r,a,b,c); now.A=-1; now.B=x; now.C=0; Treap::lzy[b]*=now; Treap::val[b]*=now; Treap::rt=Treap::merge(Treap::merge(a,b),c); } else if(opt==2){ x=read(); int a,b,c; Tag now=Tag(); Treap::Split(l,r,a,b,c); now.A=x; now.B=0; now.C=0; Treap::lzy[b]*=now; Treap::val[b]*=now; Treap::rt=Treap::merge(Treap::merge(a,b),c); } else if(opt==3){ x=read(); int a,b,c; Tag now=Tag(); Treap::Split(l,r,a,b,c); now.A=-1; now.B=0; now.C=x; Treap::lzy[b]*=now; Treap::val[b]*=now; Treap::rt=Treap::merge(Treap::merge(a,b),c); } else{ int a,b,c,d; Treap::Split(l,r,a,b,c); d=++Treap::cnt; Treap::rnd[d]=rand(); Treap::sz[d]=1; Treap::l[d]=l; Treap::r[d]=r; Treap::dfs(b,d); Treap::rt=Treap::merge(Treap::merge(a,d),c); } } while(Treap::rt){ int x; Treap::split(Treap::rt,1,x,Treap::rt); Trie::dfs(Treap::tr[x],32,0,Treap::val[x]); } return puts(""),0; }