FHQ 大法好啊!html
什麼?你說 FHQ 不能維護 LCT ? splay 也不能可持久化啊!node
就是用 FHQtreap 維護區間,reverse 的話就打個標記,裂點的時候釋放,FHQ treap 不會的點這裏ios
其實這裏什麼懶標記也就是相似線段樹的操做吧,要查兒子水錶了就把標記給兒子...git
板子在下面 (毒瘤壓行人 zjq ),看不慣就 Ctrl shift A 嘛函數
傳送門ui
//by Judge #include<cstdio> #include<iostream> #define ll long long using namespace std; const int inf=1e9+7; const int M=1e5+3; typedef int arr[M]; #ifndef Judge #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) #endif char buf[1<<21],*p1=buf,*p2=buf; inline int read(){ int x=0,f=1; char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } char sr[1<<21],z[20];int C=-1,Z; inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;} inline void print(int x,char chr=' '){ if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x; while(z[++Z]=x%10+48,x/=10); while(sr[++C]=z[Z],--Z);sr[++C]=chr; } int n,m; namespace FHQTreap{ arr pos,siz,w,fl; int rt,tot,son[M][2]; inline int Rand() { static int seed=703; return seed=int(seed*48271LL%(~0u>>1)); } inline void pushup(int x){siz[x]=siz[son[x][0]]+siz[son[x][1]]+1;} inline int newnode(int x){w[++tot]=x,siz[tot]=1,pos[tot]=Rand();return tot;} inline void pushdown(int x){swap(son[x][0],son[x][1]),fl[son[x][0]]^=1,fl[son[x][1]]^=1,fl[x]=0;} int merge(int x,int y){ if(!x||!y) return x|y; if(pos[x]<pos[y]){if(fl[x]) pushdown(x); son[x][1]=merge(son[x][1],y),pushup(x); return x;} if(fl[y]) pushdown(y); son[y][0]=merge(x,son[y][0]),pushup(y); return y; } void split(int rt,int k,int& x,int& y){ if(!rt) return x=y=0,void(); if(fl[rt]) pushdown(rt); if(siz[son[rt][0]]<k) x=rt,split(son[rt][1],k-siz[son[rt][0]]-1,son[rt][1],y); else y=rt,split(son[rt][0],k,x,son[rt][0]); pushup(rt); } void output(int x){ if(!x) return ; if(fl[x]) pushdown(x); output(son[x][0]),print(w[x]),output(son[x][1]); } } using namespace FHQTreap; int main(){ n=read(),m=read(); for(int i=1;i<=n;++i) rt=merge(rt,newnode(i)); for(int i=1,l,r,a,b,c;i<=m;++i){ l=read(),r=read(),split(rt,l-1,a,b); split(b,r-l+1,b,c),fl[b]^=1; rt=merge(a,merge(b,c)); } return output(rt),Ot(),0; }
來個例題(超級毒瘤)spa
NOI2005 維修數列code
mmp 這題真的毒瘤啊!就是一堆操做噁心你,完了讀入操做仍是字符串,煩htm
而後這裏的建樹就是比較騷的了,因爲每次都是直接加一大塊序列,若是一個一個點塞的話可能就掛掉了,那麼咱們能夠用棧來維護建樹過程blog
而後仍是懶標記,不一樣的是這裏有區間賦值的懶標記...
//by Judge #include<cstdio> #include<iostream> using namespace std; const int inf=1e9+7,M=5e5+3; inline int Max(int a,int b){return a>b?a:b;} #ifndef Judge #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) #endif char buf[1<<21],*p1=buf,*p2=buf; inline int read(){ int x=0,f=1; char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-'){ c=getchar(); if(isdigit(c)) f=-1; break; } for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } inline int cread(){ char c=getchar(),s[9]; int x=0; for(;!isupper(c);c=getchar()); for(;isupper(c)||c=='-';c=getchar()) s[++x]=c; if(s[1]=='I') return 1; if(s[1]=='D') return 2; if(s[1]=='R') return 4; if(s[1]=='G') return 5; if(s[3]=='K') return 3; if(s[3]=='X') return 6; } char sr[1<<21],z[20];int C=-1,Z; inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;} inline void print(int x,char chr='\n'){ if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x; while(z[++Z]=x%10+48,x/=10); while(sr[++C]=z[Z],--Z);sr[++C]=chr; } int n,m,op,x,l,r,a,b,c,A[M]; namespace FHQTreap{ int rt,tot,tail,pool[M],top,stk[M]; inline int Rand() { static int seed=703; return seed=int(seed*48271LL%(~0u>>1)); } struct node{ int val,pos,siz,sum,ls,rs,lmx,rmx,mx,re,co; node(){ls=rs=re=0,co=inf;} inline void init(int x){ lmx=rmx=Max(0,x),mx=sum=val=x,siz=1,pos=Rand();} inline void cover(int x){co=val=x,sum=x*siz,rmx=lmx=Max(0,sum),mx=Max(sum,x);} inline void rever(){swap(ls,rs),swap(lmx,rmx),re^=1;} }t[M]; inline int newnode(int x){ int z=tail?pool[tail--]:++tot;return t[z]=node(),t[z].init(x),z;} inline void pushup(int x){ if(!x) return ; t[x].siz=t[t[x].ls].siz+t[t[x].rs].siz+1; t[x].sum=t[t[x].ls].sum+t[t[x].rs].sum+t[x].val,t[x].mx=t[t[x].ls].rmx+t[x].val+t[t[x].rs].lmx; if(t[x].ls) t[x].mx=Max(t[x].mx,t[t[x].ls].mx); if(t[x].rs) t[x].mx=Max(t[x].mx,t[t[x].rs].mx); t[x].lmx=Max(Max(t[t[x].ls].sum+t[x].val+t[t[x].rs].lmx,t[t[x].ls].lmx),0); t[x].rmx=Max(Max(t[t[x].rs].sum+t[x].val+t[t[x].ls].rmx,t[t[x].rs].rmx),0); } inline void pushdown(int x){ if(!x) return ; if(t[x].re) t[t[x].ls].rever(),t[t[x].rs].rever(),t[x].re=0; if(t[x].co!=inf) t[t[x].ls].cover(t[x].co),t[t[x].rs].cover(t[x].co),t[x].co=inf; } int merge(int x,int y){ if(!x||!y) return x|y; pushdown(x),pushdown(y); if(t[x].pos<t[y].pos) return t[x].rs=merge(t[x].rs,y),pushup(x),x; else return t[y].ls=merge(x,t[y].ls),pushup(y),y; } void split(int rt,int k,int& x,int& y){ if(!rt) return x=y=0,void(); pushdown(rt); if(t[t[rt].ls].siz>=k) y=rt,split(t[y].ls,k,x,t[y].ls),pushup(y); else x=rt,split(t[x].rs,k-t[t[x].ls].siz-1,t[x].rs,y),pushup(x); } inline int build(int* A,int n){ int a,b,c; top=0,stk[++top]=b=newnode(A[1]); for(int i=2;i<=n;++i){ c=newnode(A[i]),a=0; while(top&&t[stk[top]].pos>t[c].pos) a=stk[top--],pushup(a); if(top) t[stk[top]].rs=c; t[c].ls=a,stk[++top]=c; if(top==1) b=c; } while(top) pushup(stk[top--]); return b; } inline void insert(){ l=read(),r=read(),split(rt,l,a,c); for(int i=1;i<=r;++i) A[i]=read(); b=build(A,r),rt=merge(a,merge(b,c)); } inline void delet(int x){ if(!x) return ; pool[++tail]=x; delet(t[x].ls),delet(t[x].rs); } inline void delet(){ l=read(),r=read(); split(rt,l-1,a,b),split(b,r,b,c); delet(b),rt=merge(a,c); } inline void cover(){ l=read(),r=read(),x=read(); split(rt,l-1,a,b),split(b,r,b,c); t[b].cover(x),rt=merge(a,merge(b,c)); } inline void rever(){ l=read(),r=read(); split(rt,l-1,a,b),split(b,r,b,c); t[b].rever(),rt=merge(a,merge(b,c)); } inline void q_sum(){ l=read(),r=read(); split(rt,l-1,a,b),split(b,r,b,c); print(t[b].sum),rt=merge(a,merge(b,c)); } } using namespace FHQTreap; int main(){ n=read(),m=read(); for(int i=1;i<=n;++i) A[i]=read(); for(rt=build(A,n);m;--m){ op=cread(); if(op==1) insert(); else if(op==2) delet(); else if(op==3) cover(); else if(op==4) rever(); else if(op==5) q_sum(); else if(op==6) print(t[rt].mx); } return Ot(),0; }
Luogu板子題,這玩意兒應該只能 \(FHQ treap\) 作
(就是好奇爲何空間要開那麼大,我算出來的話是 log 級別的啊...好吧其實也差很少,算上常數的嘛)
整體來說不是很是的 nan ,其實就是江 可持久化線段樹 和 FHQ treap 兩道紫題並在了一塊兒變成了黑題,假的【霧
但可持久化確實大可能是用了可持久化線段樹的思路,考慮新建節點,保留歷史版本什麼的...
因而就這麼愉快的 A 了此題...
聊太多了 QWQ ,開始談題目
首先你得 A 了文藝平衡樹(用 FHQ treap A 的) ,FHQ treap 不會的點這裏
其次你得學會可持久化的思想,可持久化不會的點這裏 (實際上是主席樹?可是想法相似?)
其實別的都是板子,就是 split 的時候比較特殊罷了,還有下穿標記的時候也是,須要新建節點而後連到父節點那裏
//by Judge #include<cstdio> #include<iostream> #define ll long long using namespace std; const int N=2e5; const int M=(N<<7)+3; //注意看 typedef int arr[M]; #ifndef Judge #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) #endif char buf[1<<21],*p1=buf,*p2=buf; inline ll read(){ ll x=0,f=1; char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } char sr[1<<21],z[20];int C=-1,Z; inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;} inline void print(ll x,char chr='\n'){ if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x; while(z[++Z]=x%10+48,x/=10); while(sr[++C]=z[Z],--Z);sr[++C]=chr; } int n,op,v,l,r,a,b,c; ll ans; namespace FHQTreap{ arr rt,pos,siz,fl; ll w[M],sum[M]; int now,tot,son[M][2]; inline int Rand() { static int seed=703;return seed=int(seed*48271LL%(~0u>>1));} inline int newnode(ll x=0){return w[++tot]=x,sum[tot]=x,pos[tot]=Rand(),siz[tot]=1,tot;} inline int copy(int x){ int y=newnode(); //複製節點最好單獨來一個小函數...而後裏面要 copy 的別忘 copy 全,我被這玩意兒坑了兩次 son[y][0]=son[x][0],son[y][1]=son[x][1],siz[y]=siz[x]; w[y]=w[x],sum[y]=sum[x],fl[y]=fl[x]; return y; } inline void pushup(int x){ siz[x]=siz[son[x][0]]+siz[son[x][1]]+1; sum[x]=sum[son[x][0]]+sum[son[x][1]]+w[x]; } inline void pushdown(int x){ if(!fl[x]) return; //注意看+1 if(son[x][0]) son[x][0]=copy(son[x][0]); if(son[x][1]) son[x][1]=copy(son[x][1]); fl[son[x][0]]^=1,fl[son[x][1]]^=1; swap(son[x][0],son[x][1]),fl[x]=0; } int merge(int x,int y){ if(!x||!y) return x|y; //merge 好像沒什麼特別的 if(pos[x]<pos[y]) return pushdown(x),son[x][1]=merge(son[x][1],y),pushup(x),x; else return pushdown(y),son[y][0]=merge(x,son[y][0]),pushup(y),y; } void split(int rt,int k,int& x,int& y){ //注意看+1 if(!rt) return x=y=0,void(); pushdown(rt); if(siz[son[rt][0]]>=k) y=copy(rt),split(son[y][0],k,x,son[y][0]),pushup(y); //這裏是copy了以前的節點而後直接拿他作下去了 else x=copy(rt),split(son[x][1],k-siz[son[x][0]]-1,son[x][1],y),pushup(x); //同上 } } using namespace FHQTreap; int main(){ //主函數照着題目打就行了 for(n=read();n;--n){ v=read(),op=read(); if(op==1){ l=read()^ans,r=read()^ans,split(rt[v],l,a,b); rt[++now]=merge(a,merge(newnode(r),b)); } else if(op==2){ l=read()^ans,split(rt[v],l-1,a,b); split(b,1,b,c),rt[++now]=merge(a,c); } else if(op==3){ l=read()^ans,r=read()^ans; split(rt[v],r,a,c),split(a,l-1,a,b); fl[b]^=1,rt[++now]=merge(a,merge(b,c)); } else if(op==4){ l=read()^ans,r=read()^ans; split(rt[v],r,a,c),split(a,l-1,a,b); print(ans=sum[b]),rt[++now]=merge(a,merge(b,c)); } } return Ot(),0; }