Achen大佬说不要沉迷数据结构否则智商会降低的。
从省选考完后就开始学treap,首先是自己yy了一个打了两百多行,然后debug了2个月还是3个月记不清了。
最后弃疗,去找了网上别人的代码抄了一遍。
noip考完后补常规的一段时间,羡慕Achen能20分钟打出一个treap模板,于是自己也开始走上打板子的不归路。
到了后来可以10分钟左右打出一个结构体版的treap,看了Achen的数组版treap,觉得自己结构体版的太不优秀啦,于是就换成数组版的。
然后现在有几周没有碰过treap,感觉又不会打了。。。。不过还好,大概看一下又想起来了。
先放板子,还不会打题。
结构体版:
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> #include<ctime> using namespace std; const int maxn=100000+10; int n,tot=0,ans1,ans2,root; int aa,ff;char cc; int read() { aa=0;ff=1;cc=getchar(); while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); return aa*ff; } struct Node{ int num,rnd,son[2],sum,x; }node[maxn]; void rotate(int &pos,int p) { int s=node[pos].son[p]; node[s].sum=node[pos].sum; node[pos].son[p]=node[s].son[!p]; node[s].son[!p]=pos; node[pos].sum=node[pos].x+node[node[pos].son[0]].sum+node[node[pos].son[1]].sum; pos=s; } void add(int &pos,int x) { if(!pos) { pos=++tot;node[pos].num=x;node[pos].rnd=rand(); node[pos].sum=node[pos].x=1; return ; } node[pos].sum++; if(node[pos].num==x) { node[pos].x++; return; } int p=x>node[pos].num; add(node[pos].son[p],x); if(node[node[pos].son[p]].rnd<node[pos].rnd) rotate(pos,p); } void del(int &pos,int x) { if(!pos) return; if(node[pos].num==x) { if(node[pos].x>1) { node[pos].x--;node[pos].sum--;return; } if(node[pos].son[0]*node[pos].son[1]==0) { pos=node[pos].son[0]+node[pos].son[1]; return; } int p= node[node[pos].son[1]].rnd<node[node[pos].son[0]].rnd; rotate(pos,p); node[pos].sum--; del(node[pos].son[!p],x); } else { node[pos].sum--; if(node[pos].num>x) del(node[pos].son[0],x); else del(node[pos].son[1],x); } } int qrank(int pos,int x) { if(node[pos].num==x) return node[node[pos].son[0]].sum+1; if(node[pos].num>x) return qrank(node[pos].son[0],x); return node[node[pos].son[0]].sum+node[pos].x+qrank(node[pos].son[1],x); } int qnum(int pos,int x) { if(x>node[node[pos].son[0]].sum&&x<=node[node[pos].son[0]].sum+node[pos].x) return node[pos].num; if(x<=node[node[pos].son[0]].sum) return qnum(node[pos].son[0],x); return qnum(node[pos].son[1],x-node[pos].x-node[node[pos].son[0]].sum); } void q1(int pos,int x) { if(!pos) return; if(x>node[pos].num) { ans1=node[pos].num; q1(node[pos].son[1],x); } else q1(node[pos].son[0],x); } void q2(int pos,int x) { if(!pos) return; if(x<node[pos].num) { ans2=node[pos].num; q2(node[pos].son[0],x); } else q2(node[pos].son[1],x); } int main() { srand((unsigned)time(NULL)); n=read(); int opt,x,y; for(int i=1;i<=n;++i) { opt=read();x=read(); if(opt==1) add(root,x); else if(opt==2) del(root,x); else if(opt==3) printf("%d ",qrank(root,x)); else if(opt==4) printf("%d ",qnum(root,x)); else if(opt==5) q1(root,x),printf("%d ",ans1); else q2(root,x),printf("%d ",ans2); } return 0; }
数组版:
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; const int maxn=1e5+10; int n,tot,root,ans; int sum[maxn],num[maxn],rnd[maxn],fx[maxn],son[maxn][2]; int aa,ff;char cc; int read() { aa=0;cc=getchar();ff=1; while(cc<'0'||cc>'9') { if(cc=='-') ff=-1; cc=getchar(); } while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); return aa*ff; } void rotate(int &pos,int p) { int s=son[pos][p]; sum[s]=sum[pos]; son[pos][p]=son[s][!p]; son[s][!p]=pos; sum[pos]=sum[son[pos][0]]+sum[son[pos][1]]+fx[pos]; pos=s; } void add(int &pos,int x) { if(!pos) { pos=++tot; num[pos]=x; rnd[pos]=rand(); } sum[pos]++; if(num[pos]==x) { fx[pos]++; return; } int p=x>num[pos]; add(son[pos][p],x); if(rnd[son[pos][p]]<rnd[pos]) rotate(pos,p); } void del(int &pos,int x) { if(!pos) return; if(num[pos]==x) { if(fx[pos]>1) { fx[pos]--; sum[pos]--; return; } if(son[pos][0]*son[pos][1]==0) { pos=son[pos][0]+son[pos][1]; return; } int p=rnd[son[pos][1]]<rnd[son[pos][0]]; rotate(pos,p);sum[pos]--; del(son[pos][!p],x); } else { sum[pos]--; del(son[pos][x>num[pos]],x); } } int qnum(int pos,int x) { if(x>sum[son[pos][0]]&&x<=sum[son[pos][0]]+fx[pos]) return num[pos]; if(x<=sum[son[pos][0]]) return qnum(son[pos][0],x); return qnum(son[pos][1],x-sum[son[pos][0]]-fx[pos]); } int qrank(int pos,int x) { if(x==num[pos]) return sum[son[pos][0]]+1; if(x<num[pos]) return qrank(son[pos][0],x); return sum[son[pos][0]]+fx[pos]+qrank(son[pos][1],x); } void q1(int pos,int x) { if(!pos) return; if(num[pos]<x) ans=num[pos],q1(son[pos][1],x); else q1(son[pos][0],x); } void q2(int pos,int x) { if(!pos) return; if(num[pos]>x) ans=num[pos],q2(son[pos][0],x); else q2(son[pos][1],x); } int main() { srand(1031); n=read(); int op,x; for(int i=1;i<=n;++i) { op=read();x=read(); switch(op) { case 1:add(root,x);break; case 2:del(root,x);break; case 3:printf("%d ",qrank(root,x));break; case 4:printf("%d ",qnum(root,x));break; case 5:q1(root,x);printf("%d ",ans);break; case 6:q2(root,x);printf("%d ",ans);break; } } return 0; }
而非旋treap支持split和merge很是有趣,这次直接照着Achen的板子学,感受到Achen大佬的数据结构多么优秀。
merge的时候不想用pair然后就乱搞了一搞,调了一阵子,最后强制把代码改成自己的码风。感觉不是很难打。
普通平衡树版:
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define lc son[pos][0] #define rc son[pos][1] const int maxn=1e5+10,base=28; int n,root,tot,ans; int son[maxn][2],num[maxn],sum[maxn],rnd[maxn]; int aa,ff;char cc; int read() { aa=0;ff=1;cc=getchar(); while(cc!='-'&&(cc<'0'||cc>'9')) cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); return aa*ff; } void ud(int pos){sum[pos]=sum[lc]+sum[rc]+1;} ll pr(int x,int y) {return ((ll)x<<base)+(ll)y;}//第一个ll要套在里面 int fi(ll x){return x>>base;} int se(ll x){return x-((ll)fi(x)<<base);} int merge(int x,int y) { if((ll)x*y==0) return x^y; if(rnd[x]<rnd[y]) return son[x][1]=merge(son[x][1],y),ud(x),x; else return son[y][0]=merge(x,son[y][0]),ud(y),y; } ll split(int pos,int x) { if(!pos) return 0; ll rs; if(sum[lc]>=x) { rs=split(lc,x); lc=se(rs); rs=pr(fi(rs),pos); } else { rs=split(rc,x-sum[lc]-1); rc=fi(rs); rs=pr(pos,se(rs)); } return ud(pos),rs; } int qrank(int pos,int x) { if(!pos) return 1; if(num[pos]<x) return sum[lc]+1+qrank(rc,x); return qrank(lc,x); } int qnum(int pos,int x) { if(x==sum[lc]+1) return num[pos]; if(x<=sum[lc]) return qnum(lc,x); return qnum(rc,x-sum[lc]-1); } void q1(int pos,int x) { if(!pos) return; if(num[pos]<x) ans=num[pos],q1(son[pos][1],x); else q1(son[pos][0],x); } void q2(int pos,int x) { if(!pos) return; if(num[pos]>x) ans=num[pos],q2(son[pos][0],x); else q2(son[pos][1],x); } void add(int &pos,int x) { int k=qrank(pos,x); ++tot; num[tot]=x;sum[tot]=1;rnd[tot]=rand(); ll p=split(pos,k-1); pos=merge(fi(p),tot); pos=merge(pos,se(p)); } void del(int &pos,int x) { int k=qrank(pos,x); ll p=split(pos,k-1); ll q=split(se(p),1); pos=merge(fi(p),se(q)); } int main() { srand(1031);n=read(); int op,x; while(n--) { op=read(); x=read(); switch(op) { case 1:add(root,x);break; case 2:del(root,x);break; case 3:printf("%d ",qrank(root,x));break; case 4:printf("%d ",qnum(root,x));break; case 5:q1(root,x);printf("%d ",ans);break; case 6:q2(root,x);printf("%d ",ans);break; } } return 0; }
文艺平衡树版:
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define lc son[pos][0] #define rc son[pos][1] const int maxn=1e5+10,base=28; int n,m,root,tot; int son[maxn][2],num[maxn],sum[maxn],rnd[maxn],laz[maxn]; int aa;char cc; int read() { aa=0;cc=getchar(); while(cc<'0'||cc>'9') cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); return aa; } void ud(int pos){sum[pos]=sum[lc]+sum[rc]+1;} void pd(int pos){if(!laz[pos])return;swap(lc,rc);laz[lc]^=1;laz[rc]^=1;laz[pos]=0;} ll pr(int x,int y) {return ((ll)x<<base)+(ll)y;} int fi(ll x){return x>>base;} int se(ll x){return x-((ll)fi(x)<<base);} int bld(int l,int r) { if(l>r) return 0; int mid=(l+r)>>1,pos=++tot; num[pos]=mid;sum[pos]=1;rnd[pos]=rand(); lc=bld(l,mid-1);rc=bld(mid+1,r); return ud(pos),pos; } int merge(int x,int y) { if((ll)x*y==0) return x^y; pd(x); pd(y); if(rnd[x]<rnd[y]) return son[x][1]=merge(son[x][1],y),ud(x),x; else return son[y][0]=merge(x,son[y][0]),ud(y),y; } ll split(int pos,int x) { if(!pos) return 0; ll rs; pd(pos); if(sum[lc]>=x) { rs=split(lc,x); lc=se(rs); rs=pr(fi(rs),pos); } else { rs=split(rc,x-sum[lc]-1); rc=fi(rs); rs=pr(pos,se(rs)); } return ud(pos),rs; } void rever() { int l=read(),r=read(); ll p=split(root,l-1); ll q=split(se(p),r-l+1); laz[fi(q)]^=1; root=merge(fi(p),fi(q)); root=merge(root,se(q)); } void print_ans(int pos) { if(!pos) return; pd(pos); print_ans(lc); printf("%d ",num[pos]); print_ans(rc); } int main() { srand(1031); n=read(); m=read(); root=bld(1,n); while(m--) rever(); print_ans(root); return 0; }
Achen说我的Splay不是正常人的打法,我也觉得,但是主要原因是我打Splay的时候有打treap的感觉,然后函数都是递归的不优秀。
特别烦rotate函数感觉贼难受。还需要多多练习才能熟悉啊。
普通平衡树版:
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define lc son[pos][0] #define rc son[pos][1] const int maxn=1e5+10; int n,root,tot,ans; int sum[maxn],fx[maxn],num[maxn],son[maxn][2],fa[maxn]; int aa,ff;char cc; int read() { aa=0;ff=1;cc=getchar(); while(cc<'0'||cc>'9') { if(cc=='-') ff=-1; cc=getchar(); } while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); return aa*ff; } void ud(int pos){sum[pos]=sum[lc]+sum[rc]+fx[pos];} void rotate(int pos) { int x,y,p; y=fa[x=fa[pos]]; p=son[x][1]==pos; fa[son[pos][!p]]=x;son[x][p]=son[pos][!p]; fa[x]=pos; son[pos][!p]=x; fa[pos]=y; son[y][son[y][1]==x]=pos; ud(x);ud(pos); if(root==x) root=pos; fa[root]=fa[0]=0; } void splay(int pos,int &to) { int x,y; for(;pos!=to;rotate(pos)) { y=fa[x=fa[pos]]; if(x!=to) (son[x][1]==pos ^ son[y][1]==x)? rotate(pos):rotate(x); } } void add(int &pos,int x,int f) { if(!pos) { pos=++tot; fa[pos]=f; num[pos]=x; } ++sum[pos]; if(num[pos]==x) { ++fx[pos]; return; } add(son[pos][x>num[pos]],x,pos); } void q1(int pos,int x) { if(!pos) return; if(num[pos]<x) ans=pos,q1(rc,x); else q1(lc,x); } void q2(int pos,int x) { if(!pos) return; if(num[pos]>x) ans=pos,q2(lc,x); else q2(rc,x); } int qnum(int pos,int x) { if(x>sum[lc]&&x<=sum[lc]+fx[pos]) return ans=pos,num[pos]; if(x<=sum[lc]) return qnum(lc,x); return qnum(rc,x-sum[lc]-fx[pos]); } int qrank(int pos,int x) { if(x==num[pos]) return ans=pos,sum[lc]+1; if(x<num[pos]) return qrank(lc,x); return sum[lc]+fx[pos]+qrank(rc,x); } void del(int x) { int a,b; a=b=qrank(root,x); splay(ans,root); --sum[root]; if((--fx[root])!=0) return; if(!son[root][0]) fa[root=son[root][1]]=0; else if(!son[root][1]) fa[root=son[root][0]]=0; else { qnum(root,a-1);a=ans; qnum(root,b); b=ans; splay(b,root); splay(a,son[b][0]); fa[son[a][1]]=0; son[a][1]=0; } } int main() { n=read(); int op,x; for(int i=1;i<=n;++i) { op=read(); x=read(); fa[ans=0]=sum[0]=fx[0]=0; switch(op) { case 1:add(root,x,0);break; case 2:del(x);break; case 3:printf("%d ",qrank(root,x));break; case 4:printf("%d ",qnum(root,x)); break; case 5:q1(root,x);printf("%d ",num[ans]);break; case 6:q2(root,x);printf("%d ",num[ans]);break; } if(op!=2&&ans&&ans<=tot) splay(ans,root); } return 0; }
文艺平衡树版:
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define lc son[pos][0] #define rc son[pos][1] const int maxn=1e5+10; int n,m,tot,root,ans; int sum[maxn],num[maxn],son[maxn][2],fa[maxn],laz[maxn],zz[maxn]; int aa;char cc; int read() { aa=0;cc=getchar(); while(cc<'0'||cc>'9') cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); return aa; } void ud(int pos) {sum[pos]=sum[lc]+sum[rc]+1;} void pd(int pos) {if(!laz[pos])return;swap(lc,rc);laz[lc]^=1;laz[rc]^=1;laz[pos]=0;} void rotate(int pos) { int x,y,p; y=fa[x=fa[pos]]; p=son[x][1]==pos; fa[son[pos][!p]]=x;son[x][p]=son[pos][!p]; fa[x]=pos; son[pos][!p]=x; fa[pos]=y; son[y][son[y][1]==x]=pos; ud(x); ud(pos); if(root==x) root=pos;fa[root]=fa[0]=0; } void splay(int pos,int &to) { int x,y,t=0; for(int p=pos;p!=to;p=fa[p]) zz[++t]=p; zz[++t]=to; while(t) pd(zz[t--]); for(;pos!=to;rotate(pos)) { y=fa[x=fa[pos]]; if(x!=to) (son[x][1]==pos ^ son[y][1]==x)? rotate(pos):rotate(x); } } int bld(int l,int r,int f) { if(l>r) return 0; int pos=++tot,mid=(l+r)>>1; num[pos]=mid; sum[pos]=1; fa[pos]=f; lc=bld(l,mid-1,pos); rc=bld(mid+1,r,pos); return ud(pos),pos; } int qnum(int pos,int x) { pd(pos);if(x<1||x>sum[pos]) return ans=-1; if(x==sum[lc]+1) return num[ans=pos]; if(x<=sum[lc]) return qnum(lc,x); return qnum(rc,x-sum[lc]-1); } void rever() { int l=read(),r=read(),a,b; ans=0; qnum(root,l-1); a=ans; qnum(root,r+1); b=ans; if(l==1&&r==n) laz[root]^=1; else if(l==1) splay(b,root),laz[son[b][0]]^=1; else if(r==n) splay(a,root),laz[son[a][1]]^=1; else { splay(b,root); splay(a,son[b][0]); laz[son[a][1]]^=1; } } void print_ans(int pos) { if(!pos) return; pd(pos); print_ans(lc); printf("%d ",num[pos]); print_ans(rc); } int main() { n=read(); m=read(); root=bld(1,n,0); while(m--) rever(); print_ans(root); return 0; }
bzoj1503郁闷的出纳员
没有什么好说的,就是一个模板题,treap、非旋treap、splay都可以。
一个技巧:对于所有员工工资上涨下降可以直接改变工资的最低值,但是注意加入一个员工时对员工工资的处理,还有查询第k大输出-1的情况。
普通treap:
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define lc son[pos][0] #define rc son[pos][1] const int maxn=1e5+10; int n,slry,now,tot,root,ans,delans; char s[23]; int sum[maxn],num[maxn],fx[maxn],son[maxn][2],rnd[maxn]; int aa;char cc; int read() { aa=0;cc=getchar(); while(cc<'0'||cc>'9') cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); return aa; } void rotate(int& pos,int p) { int s=son[pos][p]; sum[s]=sum[pos]; son[pos][p]=son[s][!p]; son[s][!p]=pos; sum[pos]=sum[lc]+sum[rc]+fx[pos]; pos=s; } void add(int& pos,int x) { if(!pos) { pos=++tot; num[pos]=x; rnd[pos]=rand(); } ++sum[pos]; if(num[pos]==x) { ++fx[pos]; return; } int p=x>num[pos]; add(son[pos][p],x); if(rnd[son[pos][p]]<rnd[pos]) rotate(pos,p); } void del(int &pos,int x) { if(!pos) return; if(num[pos]==x) { if(fx[pos]>1) { --sum[pos]; --fx[pos]; return; } if((ll)son[pos][0]*son[pos][1]==0) { pos=son[pos][0]^son[pos][1]; return; } int p=rnd[rc] < rnd[lc]; rotate(pos,p); --sum[pos]; del(son[pos][!p],x); } else { --sum[pos]; del(son[pos][x>num[pos]],x); } } int qnum(int pos,int x) { if(x<=0) return -1+now-slry; if(x>sum[lc]&&x<=sum[lc]+fx[pos]) return num[pos]; if(x<=sum[lc]) return qnum(lc,x); return qnum(rc,x-sum[lc]-fx[pos]); } int q(int pos) { if(lc) return q(lc); return num[pos]; } void getadd(int x) { if(x<slry) return; add(root,x+now-slry); } void getdel(int x) { int num; while(root&&(num=q(root))<x) { ++delans; del(root,num); } } int main() { srand(1031); n=read(); now=slry=read(); for(int i=1;i<=n;++i) { scanf("%s",s+1); switch(s[1]) { case 'I':getadd(read());break; case 'A':now-=read(); break; case 'S':now+=read();getdel(now);break; case 'F':printf("%d ",qnum(root,sum[root]-read()+1)-now+slry);break; } } printf("%d",delans); return 0; }
非旋treap:
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define lc son[pos][0] #define rc son[pos][1] const int maxn=1e5+10,base=25; int n,slry,now,tot,root,ans,delans; char s[23]; int sum[maxn],num[maxn],son[maxn][2],rnd[maxn]; int aa;char cc; int read() { aa=0;cc=getchar(); while(cc<'0'||cc>'9') cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); return aa; } void ud(int pos) {sum[pos]=sum[lc]+sum[rc]+1;} ll pr(int x,int y) {return ((ll)x<<base)+(ll)y;} int fi(ll x) {return x>>base;} int se(ll x) {return x-((ll)fi(x)<<base);} int merge(int x,int y) { if((ll)x*y==0) return x^y; if(rnd[x]<rnd[y]) return son[x][1]=merge(son[x][1],y),ud(x),x; return son[y][0]=merge(x,son[y][0]),ud(y),y; } ll split(int pos,int x) { if(!pos) return 0; ll rs; if(sum[lc]>=x) { rs=split(lc,x); lc=se(rs); rs=pr(fi(rs),pos); } else { rs=split(rc,x-sum[lc]-1); rc=fi(rs); rs=pr(pos,se(rs)); } return ud(pos),rs; } int qrank(int pos,int x) { if(!pos) return 1; if(num[pos]<x) return sum[lc]+1+qrank(rc,x); return qrank(lc,x); } int qnum(int pos,int x) { if(x<=0) return -1+now-slry; if(x>sum[lc]&&x<=sum[lc]+1) return num[pos]; if(x<=sum[lc]) return qnum(lc,x); return qnum(rc,x-sum[lc]-1); } void getadd(int &pos,int x) { if(x<slry) return; x+=now-slry; int k=qrank(pos,x); ++tot; num[tot]=x;sum[tot]=1;rnd[tot]=rand(); ll p=split(pos,k-1); pos=merge(fi(p),tot); pos=merge(pos,se(p)); } void getdel(int &pos,int x) { int k=qrank(pos,x); delans+=k-1; if(k==1) return; ll p=split(root,k-1); pos=se(p); } int main() { srand(1031); n=read(); now=slry=read(); for(int i=1;i<=n;++i) { scanf("%s",s+1); switch(s[1]) { case 'I':getadd(root,read());break; case 'A':now-=read(); break; case 'S':now+=read();getdel(root,now);break; case 'F':printf("%d ",qnum(root,sum[root]-read()+1)-now+slry);break; } } printf("%d",delans); return 0; }
LCT
只要会Splay,LCT就很好打,第一次打是12月18日,因为直接是抄的板,所以1A,
昨天打SAM+LCT的时候发现有点快忘了LCT怎么打,就重新打了LCT,
然后link那里写成了newroot(y),fa[x]=y,所以死WA
然后用二分拼接代码法很快找到了bug
#include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define lc son[pos][0] #define rc son[pos][1] const int maxn=3e5+10; int n,m,tot; int fa[maxn],son[maxn][2],zz[maxn],sum[maxn],num[maxn],laz[maxn]; char cc;ll ff; template<typename T>void read(T& aa) { aa=0;ff=1; cc=getchar(); while(cc!='-'&&(cc<'0'||cc>'9')) cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } bool isroot(int pos) {return son[fa[pos]][0]!=pos&&son[fa[pos]][1]!=pos;} void ud(int pos) {sum[pos]=sum[lc]^sum[rc]^num[pos];} void pd(int pos) { if(!laz[pos]) return; laz[pos]=0; swap(lc,rc); if(lc) laz[lc]^=1; if(rc) laz[rc]^=1; } void rotate(int pos) { int x,y,p;y=fa[x=fa[pos]]; p=son[x][1]==pos; if(!isroot(x)) son[y][son[y][1]==x]=pos;fa[pos]=y; son[x][p]=son[pos][!p]; fa[son[pos][!p]]=x; son[pos][!p]=x; fa[x]=pos; ud(x); ud(pos); } void splay(int pos) { int x,y,t=0; for(x=pos;!isroot(x);x=fa[x]) zz[++t]=x; zz[++t]=x; while(t) pd(zz[t--]); for(;!isroot(pos);rotate(pos)) { y=fa[x=fa[pos]]; if(!isroot(x)) (son[x][1]==pos)^(son[y][1]==x)? rotate(pos):rotate(x); } } void access(int pos) { for(int t=0;pos;pos=fa[t=pos]) { splay(pos); rc=t; ud(pos); } } int findroot(int pos) { access(pos); splay(pos); while(lc) pos=lc; return pos; } void newroot(int pos) { access(pos); splay(pos); laz[pos]^=1; } void lk(int x,int y) { if(findroot(x)==findroot(y)) return ; newroot(x); fa[x]=y; } void del(int x,int y) { newroot(x); access(y); splay(y); if(son[y][0]==x) fa[x]=son[y][0]=0; } int Yth(int x,int y) { newroot(x); access(y); splay(y); return sum[y]; } void mdf(int x,int y) { splay(x); num[x]=y; ud(x); } int main() { read(n); read(m); int op,x,y; for(int i=1;i<=n;++i) read(num[i]); for(int i=1;i<=m;++i) { read(op); read(x); read(y); switch(op) { case 0:printf("%d ",Yth(x,y)); break; case 1:lk(x,y); break; case 2:del(x,y); break; case 3:mdf(x,y); break; } } return 0; }
可持久化treap
就是在merge和split的时候新开一下节点就可以了
克服了心理障碍就没什么难打的
#include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define lc son[pos][0] #define rc son[pos][1] const ll maxn=1e6+7,base=25,INF=2147483647; int n,tot,root[maxn]; int num[25*maxn],sum[25*maxn],rnd[25*maxn],son[25*maxn][2]; char cc;ll ff; template<typename T>void read(T& aa) { aa=0;ff=1; cc=getchar(); while(cc!='-'&&(cc<'0'||cc>'9')) cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } ll pr(ll x,ll y) {return (x<<base)+y;} ll fi(ll x) {return x>>base;} ll se(ll x) {return x-(fi(x)<<base);} void ud(int pos) {sum[pos]=sum[lc]+sum[rc]+1;} void copy(int pos,int x) { num[pos]=num[x]; sum[pos]=sum[x]; rnd[pos]=rnd[x]; lc=son[x][0]; rc=son[x][1]; } bool exit(int pos,int x) { while(num[pos]!=x&&pos) { if(x<num[pos]) pos=lc; else pos=rc; } return pos; } int merge(int x,int y) { if((ll)x*y==0) return x^y; int pos=++tot; if(rnd[x]<rnd[y]) copy(pos,x),rc=merge(rc,y); else copy(pos,y),lc=merge(x,lc); return ud(pos),pos; } ll split(int p,int x) { if(!p) return 0; int pos=++tot; copy(pos,p); ll rs; if(sum[lc]>=x) { rs=split(lc,x); lc=se(rs); rs=pr(fi(rs),pos); } else { rs=split(rc,x-sum[lc]-1); rc=fi(rs); rs=pr(pos,se(rs)); } return ud(pos),rs; } int qrank(int pos,int x) { if(!pos) return 1; if(num[pos]<x) return sum[lc]+1+qrank(rc,x); return qrank(lc,x); } int qnum(int pos,int x) { if(x==sum[lc]+1) return num[pos]; if(x<=sum[lc]) return qnum(lc,x); return qnum(rc,x-sum[lc]-1); } void add(int &pos,int x) { int k=qrank(pos,x); ll p=split(pos,k-1); num[++tot]=x;sum[tot]=1;rnd[tot]=rand(); pos=merge(fi(p),tot); pos=merge(pos,se(p)); } void del(int &pos,int x) { if(!exit(pos,x)) return; int k=qrank(pos,x); ll p=split(pos,k-1); ll q=split(se(p),1); pos=merge(fi(p),se(q)); } int q1(int pos,int x) { if(!pos) return -INF; if(num[pos]<x) return max(q1(rc,x),num[pos]); else return q1(lc,x); } int q2(int pos,int x) { if(!pos) return INF; if(num[pos]>x) return min(q2(lc,x),num[pos]); else return q2(rc,x); } int main() { srand(1031); read(n);int op,x,p; for(int i=1;i<=n;++i) { read(p); read(op); read(x); root[i]=root[p]; switch(op) { case 1:add(root[i],x);break; case 2:del(root[i],x); break; case 3:printf("%d ",qrank(root[i],x));break; case 4:printf("%d ",qnum(root[i],x));break; case 5:printf("%d ",q1(root[i],x));break; case 6:printf("%d ",q2(root[i],x));break; } if(!root[i]) root[i]=merge(son[root[i]][0],son[root[i]][1]); } return 0; } /* 10 0 1 9 1 1 3 1 1 10 2 4 2 3 3 9 3 1 2 6 4 1 6 2 9 8 6 3 4 5 8 */
树上莫队(uoj58糖果公园)
#include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long const int maxn=1e5+7,maxs=21; int n,m,q,size; ll nowans,v[maxn],w[maxn],c[maxn],ans[maxn]; char cc;ll ff; template<typename T>void read(T& aa) { aa=0;ff=1; cc=getchar(); while(cc!='-'&&(cc<'0'||cc>'9')) cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } int dep[maxn],fa[maxn][maxs],dfn[maxn],dfsclock; int bel[maxn],totb; int zz[maxn],top; struct Ask{ int x,y,id,t; Ask(){} Ask(int x,int y,int id,int t):x(x),y(y),id(id),t(t){} }ask[maxn]; int totask; bool cmp(const Ask& a,const Ask& b) { return bel[a.x]==bel[b.x]? (bel[a.y]==bel[b.y]? a.t<b.t:bel[a.y]<bel[b.y]) : bel[a.x]<bel[b.x]; } struct Mdf{ int pos,now,last; Mdf(){} Mdf(int pos,int now,int last):pos(pos),now(now),last(last){ } }mdf[maxn]; int totmdf; int fir[maxn],nxt[2*maxn],to[2*maxn],e=0; void add(int x,int y) { to[++e]=y;nxt[e]=fir[x];fir[x]=e; to[++e]=x;nxt[e]=fir[y];fir[y]=e; } void together(int l,int &r) { ++totb; while(r>l) bel[zz[r--]]=totb; } void dfs(int pos,int d) { int bot=top,y,z; dfn[pos]=++dfsclock; dep[pos]=d; for(int i=1;i<20;++i) fa[pos][i]=fa[fa[pos][i-1]][i-1]; for(y=fir[pos];y;y=nxt[y]) { if((z=to[y])==fa[pos][0]) continue; fa[z][0]=pos; dfs(z,d+1); if(top-bot>=size) together(bot,top); } zz[++top]=pos; } int get_lca(int x,int y) { if(dep[x]!=dep[y]) { if(dep[x]<dep[y]) swap(x,y); for(int i=19;(~i)&&dep[x]>dep[y];--i) if(dep[fa[x][i]]>=dep[y]) x=fa[x][i]; } if(x==y) return x; for(int i=19;~i;--i) if(fa[x][i]!=fa[y][i]) { x=fa[x][i];y=fa[y][i]; } return fa[x][0]; } bool vis[maxn];int sum[maxn]; void chge(int pos,int p) { if(p) { sum[c[pos]]++; nowans+=(ll)w[sum[c[pos]]]*v[c[pos]]; } else { nowans-=(ll)w[sum[c[pos]]]*v[c[pos]]; sum[c[pos]]--; } } void fz(int x,int y) { int lca=get_lca(x,y); for(int i=x;i!=lca;i=fa[i][0]) chge(i,vis[i]^=1); for(int i=y;i!=lca;i=fa[i][0]) chge(i,vis[i]^=1); } int main() { read(n); read(m); read(q); size=0.5*pow(n,2.0/3); int op,x,y; for(int i=1;i<=m;++i) read(v[i]); for(int i=1;i<=n;++i) read(w[i]); for(int i=1;i<n;++i) { read(x); read(y); add(x,y); } dfs(1,1); while(top) bel[zz[top--]]=totb; for(int i=1;i<=n;++i) read(c[i]); for(int i=1;i<=q;++i) { read(op); read(x); read(y); if(!op) {mdf[++totmdf]=Mdf(x,y,c[x]);c[x]=y;} else { if(dfn[x]>dfn[y]) swap(x,y); ++totask; ask[totask]=Ask(x,y,totask,totmdf); } } for(int i=totmdf;i;--i) c[mdf[i].pos]=mdf[i].last; sort(ask+1,ask+totask+1,cmp); int nowt=0,pos,lastx=ask[1].x,lasty=ask[1].y; fz(lastx,lasty); for(int i=1;i<=totask;++i) { x=ask[i].x; y=ask[i].y; while(nowt>ask[i].t) { pos=mdf[nowt].pos; if(vis[pos]) chge(pos,0); c[pos]=mdf[nowt--].last; if(vis[pos]) chge(pos,1); } while(nowt<ask[i].t) { pos=mdf[++nowt].pos; if(vis[pos]) chge(pos,0); c[pos]=mdf[nowt].now; if(vis[pos]) chge(pos,1); } fz(lastx,x); fz(lasty,y); pos=get_lca(x,y); chge(pos,vis[pos]^=1); ans[ask[i].id]=nowans; chge(pos,vis[pos]^=1); lastx=x; lasty=y; } for(int i=1;i<=totask;++i) printf("%lld ",ans[i]); return 0; } /* 4 3 5 1 9 2 7 6 5 1 2 3 3 1 3 4 1 2 3 2 1 1 2 1 4 2 0 2 1 1 1 2 1 4 2 */
一些Achen几万年前就A过的模板题:
bzoj1208宠物收养所
treap/splay随便维护一下即可
注意bz上交不能有srand,为此debug2h
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define db double #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) #define lc son[pos][0] #define rc son[pos][1] const int maxn=1e5+7; const ll mod=1000000; int n,root,now=-1,tot; ll ans,INF=1e14; int son[maxn][2],rnd[maxn];ll num[maxn]; char cc; ll ff; template<typename T>void read(T& aa) { aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } void rotate(int &pos,int p) { int s=son[pos][p]; son[pos][p]=son[s][!p]; son[s][!p]=pos; pos=s; } void add(int &pos,ll x) { if(!pos) { pos=++tot; num[pos]=x; rnd[pos]=rand()*rand(); return; } int p=x>num[pos]; add(son[pos][p],x); if(rnd[son[pos][p]]<rnd[pos]) rotate(pos,p); } void del(int &pos,ll x) { if(!pos) return; if(num[pos]==x) { if((ll)lc*rc==0) { pos=lc^rc; return; } int p=rnd[rc]<rnd[lc]; rotate(pos,p); del(son[pos][!p],x); } else del(son[pos][x>num[pos]],x); } ll q1(int pos,ll x) { if(!pos) return -INF; if(num[pos]<=x) return max(q1(rc,x),num[pos]); return q1(lc,x); } ll q2(int pos,ll x) { if(!pos) return INF; if(num[pos]>=x) return min(q2(lc,x),num[pos]); return q2(rc,x); } int main() { read(n); ll x,y,p1,p2; For(i,1,n) { read(x); read(y); if(x==now||(!root)) { add(root,y); now=x; } else { p1=q1(root,y); p2=q2(root,y); if(y-p1<=p2-y) del(root,p1),ans+=(y-p1); else del(root,p2),ans+=(p2-y); ans%=mod; } } printf("%lld",ans); return 0; }
bzoj2733永无乡
splay+启发式合并
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define db double #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) #define lc son[pos][0] #define rc son[pos][1] const int maxn=1e5+7; int n,m; char s[maxn]; int num[maxn],sum[maxn],fa[maxn],son[maxn][2]; char cc; ll ff; template<typename T>void read(T& aa) { aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } int f[maxn]; int find(int x){return x==f[x]? x:f[x]=find(f[x]);} void rotate(int pos) { int x,y,p; y=fa[x=fa[pos]]; p= son[x][1]==pos; fa[son[pos][!p]]=x; son[x][p]=son[pos][!p]; fa[x]=pos; son[pos][!p]=x; fa[pos]=y; son[y][son[y][1]==x]=pos; sum[pos]=sum[x]; sum[x]=sum[son[x][0]]+sum[son[x][1]]+1; } void add(int &pos,int x,int f) { if(!pos) { pos=x; fa[pos]=f; return; } sum[pos]+=sum[x]; add(son[pos][num[x]>num[pos]],x,pos); } void splay(int pos) { int x,y; for(;fa[pos];rotate(pos)) { y=fa[x=fa[pos]]; if(y) (son[x][1]==pos ^ son[y][1]==x)? rotate(pos):rotate(x); } } void insert(int root,int pos) { if(!pos) return; int lson=lc,rson=rc; fa[lc]=fa[rc]=0; lc=rc=0; sum[pos]=1; add(root,pos,0); insert(root,lson); insert(root,rson); } void lik(int x,int y) { if(find(x)==find(y)) return; f[find(x)]=find(y); splay(x);splay(y); if(sum[x]<sum[y]) swap(x,y); insert(x,y); } int qnum(int pos,int x) { if(x==sum[lc]+1) return pos; if(x<=sum[lc]) return qnum(lc,x); return qnum(rc,x-sum[lc]-1); } int q(int pos,int x) { splay(pos); if(x>sum[pos]) return -1; return qnum(pos,x); } int main() { read(n); read(m); int x,y; For(i,1,n) f[i]=i,read(num[i]=i),sum[i]=1; For(i,1,m) { read(x); read(y); lik(x,y); } read(m); For(i,1,m) { scanf("%s",s+1); read(x); read(y); if(s[1]=='B') lik(x,y); else printf("%d ",q(x,y)); } return 0; } /* 5 1 4 3 2 5 1 1 2 7 Q 3 2 Q 2 1 B 2 3 B 1 5 Q 2 1 Q 2 4 Q 2 3 */
bzoj2843极地旅行社
LCT
一开始1e5+7打+的时候按成了Backspace,结果打成1e7然后MLE了
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define db double #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) #define lc son[pos][0] #define rc son[pos][1] const int maxn=1e5+7; int n,m,f[maxn]; char s[maxn]; int fa[maxn],sum[maxn],son[maxn][2],num[maxn],laz[maxn]; char cc; ll ff; template<typename T>void read(T& aa) { aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } int find(int x){return x==f[x]? x:f[x]=find(f[x]);} bool isroot(int pos){return son[fa[pos]][0]!=pos&&son[fa[pos]][1]!=pos;} void ud(int pos) {sum[pos]=sum[lc]+sum[rc]+num[pos];} void pd(int pos) { if(!laz[pos]) return; swap(lc,rc); laz[pos]=0; if(lc) laz[lc]^=1; if(rc) laz[rc]^=1; } void rotate(int pos) { int x,y,p; y=fa[x=fa[pos]]; p=son[x][1]==pos; if(!isroot(x)) son[y][son[y][1]==x]=pos; fa[pos]=y; son[x][p]=son[pos][!p]; fa[son[x][p]]=x; son[pos][!p]=x; fa[x]=pos; ud(x); ud(pos); } int zz[maxn]; void splay(int pos) { int x,y,t=0; for(x=pos;!isroot(x);x=fa[x]) zz[++t]=x; zz[++t]=x; while(t) pd(zz[t--]); for(;!isroot(pos);rotate(pos)) { y=fa[x=fa[pos]]; if(!isroot(x)) (son[x][1]==pos ^ son[y][1]==x)? rotate(pos):rotate(x); } } void access(int pos) { for(int t=0;pos;pos=fa[t=pos]) { splay(pos); rc=t; ud(pos); } } void newroot(int pos) { access(pos); splay(pos); laz[pos]^=1; } void lik(int x,int y) { if(find(x)==find(y)) { printf("no "); return; } printf("yes "); newroot(x); fa[x]=y; f[find(x)]=find(y); } void chge(int pos,int y) { splay(pos); num[pos]=y; ud(pos); } int q(int x,int y) { if(find(x)!=find(y)) return -1; newroot(x); access(y); splay(y); return sum[y]; } int main() { read(n); int x,y,ans; For(i,1,n) read(num[i]),f[i]=i; read(m); For(i,1,m) { scanf("%s",s+1); read(x); read(y); if(s[1]=='b') lik(x,y); else if(s[1]=='p') chge(x,y); else { ans=q(x,y); if(ans==-1) printf("impossible "); else printf("%d ",ans); } } return 0; } /* 5 4 2 4 5 6 10 excursion 1 1 excursion 1 2 bridge 1 2 excursion 1 2 bridge 3 4 bridge 3 5 excursion 4 5 bridge 1 3 excursion 2 4 excursion 2 5 */
bzoj2002 弹飞绵羊
LCT:
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define db double #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) #define lc son[pos][0] #define rc son[pos][1] const int maxn=2e5+7; int n,m,sum[maxn],fa[maxn],son[maxn][2]; char cc; ll ff; template<typename T>void read(T& aa) { aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } void ud(int pos) {sum[pos]=sum[lc]+sum[rc]+1;} bool isroot(int pos){return son[fa[pos]][0]!=pos&&son[fa[pos]][1]!=pos;} void rotate(int pos) { int x,y,p; y=fa[x=fa[pos]]; p=son[x][1]==pos; if(!isroot(x)) son[y][son[y][1]==x]=pos; fa[pos]=y; son[x][p]=son[pos][!p]; fa[son[pos][!p]]=x; son[pos][!p]=x; fa[x]=pos; ud(x); ud(pos); } void splay(int pos) { int x,y; for(;!isroot(pos);rotate(pos)) { y=fa[x=fa[pos]]; if(!isroot(x)) (son[x][1]==pos^son[y][1]==x)? rotate(pos):rotate(x); } } void access(int pos) { for(int t=0;pos;pos=fa[t=pos]) { splay(pos); rc=t; ud(pos); } } void cut(int x) { access(x); splay(x); fa[son[x][0]]=0; son[x][0]=0; ud(x); } int main() { read(n); int op,x,y; For(i,1,n+1) sum[i]=1; For(i,1,n) { read(x); fa[i]=min(i+x,n+1); } read(m); For(i,1,m) { read(op); read(x); x++; if(op==1) { access(x); splay(x); printf("%d ",sum[son[x][0]]); } else { read(y); y=min(y+x,n+1); cut(x); fa[x]=y; } } return 0; }
Splay维护括号序列:
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define db double #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) #define lc son[pos][0] #define rc son[pos][1] const int maxn=4e5+7; int n,m,root,num[maxn],sum[maxn],fa[maxn],son[maxn][2]; char cc; ll ff; template<typename T>void read(T& aa) { aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } int fir[maxn],nxt[maxn],to[maxn],e=0; void add(int x,int y) { to[++e]=y;nxt[e]=fir[x];fir[x]=e; } int dfn[maxn],end[maxn],dfn_clock; void dfs(int pos) { num[dfn[pos]=++dfn_clock]=1; for(int y=fir[pos];y;y=nxt[y]) dfs(to[y]); num[end[pos]=++dfn_clock]=-1; } void ud(int pos) {sum[pos]=num[pos]+sum[lc]+sum[rc];} void bld(int &pos,int l,int r,int f) { if(l>r) {pos=0;return;} pos=(l+r)>>1; fa[pos]=f; bld(lc,l,pos-1,pos); bld(rc,pos+1,r,pos); ud(pos); } void rotate(int pos) { int x,y,p; y=fa[x=fa[pos]]; p=son[x][1]==pos; if(y) son[y][son[y][1]==x]=pos; else root=pos; fa[pos]=y; son[x][p]=son[pos][!p]; fa[son[pos][!p]]=x; son[pos][!p]=x; fa[x]=pos; ud(x); ud(pos); } void splay(int pos) { int x,y; for(;fa[pos];rotate(pos)) { y=fa[x=fa[pos]]; if(y) (son[x][1]==pos^son[y][1]==x)? rotate(pos):rotate(x); } } int split(int pos) { splay(pos); int rs; fa[rs=rc]=0; rc=0; ud(pos); return rs; } void merge(int x,int y) { splay(x); splay(y); while(son[x][1]) x=son[x][1]; splay(x); fa[y]=x; son[x][1]=y; ud(x); } int q(int pos) { splay(pos); pos=lc; while(rc) pos=rc; return pos; } int main() { read(n); int op,x,y,l,r; For(i,1,n) { read(x); x=min(i+x,n+1); add(x,i); } dfs(n+1); bld(root,1,dfn_clock,0); son[2*n+3][0]=root; fa[root]=2*n+3; ud(2*n+3); root=2*n+3; son[2*n+4][1]=root; fa[root]=2*n+4; ud(2*n+4); root=2*n+4; read(m); For(i,1,m) { read(op); read(x); ++x; if(op==1) { splay(x=dfn[x]); printf("%d ",sum[son[x][0]]); } else { read(y); y=min(y+x,n+1); l=q(dfn[x]); split(l); r=split(end[x]); merge(l,r); split(dfn[y]); merge(dfn[y],end[x]); merge(end[x],end[y]); } } return 0; }
bzoj3786 星系探索
splay维护括号序列(下面是一份还T着的代码)
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define db double #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) #define lc son[pos][0] #define rc son[pos][1] const int maxn=2e5+7; int n,m,root; char s[13]; ll w[maxn],d[maxn],tot[maxn],sum[maxn],num[maxn],laz[maxn]; int son[maxn][2],fa[maxn]; char cc; ll ff; template<typename T>void read(T& aa) { aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } int fir[maxn],nxt[maxn],to[maxn],e=0; void add(int x,int y) { to[++e]=y;nxt[e]=fir[x];fir[x]=e; } int dfn[maxn],end[maxn],dfn_clock; void dfs(int pos) { num[dfn[pos]=++dfn_clock]=w[pos]; d[dfn_clock]=1; for(int y=fir[pos];y;y=nxt[y]) dfs(to[y]); num[end[pos]=++dfn_clock]=-w[pos]; d[dfn_clock]=-1; } void ud(int pos) {sum[pos]=num[pos]+sum[lc]+sum[rc];tot[pos]=d[pos]+tot[lc]+tot[rc];} void add_tag(int pos,ll x) { sum[pos]+=tot[pos]*x; num[pos]+=d[pos]*x;// laz[pos]+=x; } void pd(int pos) { if(!laz[pos]) return; if(lc) add_tag(lc,laz[pos]); if(rc) add_tag(rc,laz[pos]); laz[pos]=0; } void bld(int &pos,int l,int r,int f) { if(l>r) {pos=0;return;} pos=(l+r)>>1; fa[pos]=f; bld(lc,l,pos-1,pos); bld(rc,pos+1,r,pos); ud(pos); } void rotate(int pos) { int x,y,p; y=fa[x=fa[pos]]; p=son[x][1]==pos; if(y) son[y][son[y][1]==x]=pos; else root=pos; fa[pos]=y; son[x][p]=son[pos][!p]; fa[son[pos][!p]]=x; son[pos][!p]=x; fa[x]=pos; ud(x); ud(pos); } int zz[maxn]; void splay(int pos) { int t=0,x,y; for(int p=pos;p;p=fa[p]) zz[++t]=p; while(t) pd(zz[t--]); for(;fa[pos];rotate(pos)) { y=fa[x=fa[pos]]; if(y) (son[x][1]==pos^son[y][1]==x)? rotate(pos):rotate(x); } } int split(int pos) { splay(pos); int rs; fa[rs=rc]=0; rc=0; ud(pos); return rs; } void merge(int x,int y) { splay(x); splay(y);// while(son[x][1]) pd(x),x=son[x][1]; splay(x); fa[y]=x; son[x][1]=y; ud(x); } int q(int pos) { splay(pos); pos=lc; while(rc) pd(pos),pos=rc; return pos; } int main() { read(n); ll x,y,l,r; For(i,2,n) { read(x); add(x,i); } For(i,1,n) read(w[i]); dfs(1); bld(root,1,dfn_clock,0); son[2*n+3][0]=root; fa[root]=2*n+3; ud(2*n+3); root=2*n+3; son[2*n+4][1]=root; fa[root]=2*n+4; ud(2*n+4); root=2*n+4; read(m); For(i,1,m) { scanf("%s",s+1); read(x); if(s[1]=='Q') { splay(x=dfn[x]); printf("%lld ",sum[son[x][0]]+num[x]); } else if(s[1]=='C') { read(y); l=q(dfn[x]); split(l); r=split(end[x]); split(dfn[y]); merge(dfn[y],dfn[x]); merge(dfn[x],end[y]); } else { read(y); l=q(dfn[x]); split(l); r=split(end[x]); splay(dfn[x]); add_tag(dfn[x],y); merge(l,dfn[x]); merge(dfn[x],r); } } return 0; } /* 3 1 1 4 5 7 5 Q 2 F 1 3 Q 2 C 2 3 Q 2 */
bzoj4530 大融合
LCT维护子树信息,又把rotate的p和!p写错了,debug真烦
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define db double #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) #define lc son[pos][0] #define rc son[pos][1] const int maxn=1e5+7; int n,m,fa[maxn],sum[maxn],tot[maxn],son[maxn][2],laz[maxn]; char s[13]; char cc; ll ff; template<typename T>void read(T& aa) { aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } bool isroot(int pos) {return son[fa[pos]][0]!=pos&&son[fa[pos]][1]!=pos;} void ud(int pos){sum[pos]=sum[lc]+sum[rc]+tot[pos]+1;} void pd(int pos) { if(!laz[pos]) return; swap(lc,rc); laz[lc]^=1; laz[rc]^=1; laz[pos]=0; } void rotate(int pos) { int x,y,p; y=fa[x=fa[pos]]; p=son[x][1]==pos; if(!isroot(x)) son[y][son[y][1]==x]=pos; fa[pos]=y; son[x][p]=son[pos][!p]; fa[son[pos][!p]]=x; son[pos][!p]=x; fa[x]=pos; ud(x); ud(pos); } int zz[maxn]; void splay(int pos) { int x,y,p,t=0; for(p=pos;!isroot(p);p=fa[p]) zz[++t]=p; zz[++t]=p; while(t) pd(zz[t--]); for(;!isroot(pos);rotate(pos)) { y=fa[x=fa[pos]]; if(!isroot(x)) (son[x][1]==pos^son[y][1]==x)? rotate(pos):rotate(x); } } void access(int pos) { for(int t=0;pos;pos=fa[t=pos]) { splay(pos); tot[pos]+=sum[rc]-sum[t]; rc=t; ud(pos); } } void newroot(int pos) { access(pos); splay(pos); laz[pos]^=1; } void lk(int x,int y) { newroot(x); newroot(y); fa[y]=x; tot[x]+=sum[y]; ud(x); } int main() { read(n); read(m); int x,y; For(i,1,n) sum[i]=1; For(i,1,m) { scanf("%s",s+1); read(x); read(y); if(s[1]=='A') lk(x,y); else { newroot(x); newroot(y); printf("%lld ",(ll)(sum[y]-sum[x])*sum[x]); } } return 0; }
UOJ207 共价大爷游长沙
LCT维护子树信息
num和sum没分清
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define db double #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) #define lc son[pos][0] #define rc son[pos][1] const int maxn=3e5+7; int n,m,son[maxn][2],fa[maxn],laz[maxn]; ll now,sum[maxn],num[maxn]; char cc; ll ff; template<typename T>void read(T& aa) { aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } struct Node{ int x,y;ll num; Node(){} Node(int x,int y,ll num):x(x),y(y),num(num){} }node[maxn]; int tot; bool isroot(int pos){return son[fa[pos]][0]!=pos&&son[fa[pos]][1]!=pos;} void ud(int pos){sum[pos]=sum[lc]^sum[rc]^num[pos];} void pd(int pos) { if(!laz[pos]) return; swap(lc,rc); if(lc) laz[lc]^=1; if(rc) laz[rc]^=1; laz[pos]=0; } void rotate(int pos) { int x,y,p; y=fa[x=fa[pos]]; p=son[x][1]==pos; if(!isroot(x)) son[y][son[y][1]==x]=pos; fa[pos]=y; son[x][p]=son[pos][!p]; fa[son[pos][!p]]=x; son[pos][!p]=x; fa[x]=pos; ud(x); ud(pos); } int zz[maxn]; void splay(int pos) { int x,y,p,t=0; for(p=pos;!isroot(p);p=fa[p]) zz[++t]=p; zz[++t]=p; while(t) pd(zz[t--]); for(;!isroot(pos);rotate(pos)) { y=fa[x=fa[pos]]; if(!isroot(x)) (son[x][1]==pos^son[y][1]==x)? rotate(pos):rotate(x); } } void access(int pos) { for(int t=0;pos;pos=fa[t=pos]) { splay(pos); num[pos]^=(sum[rc]^sum[t]);// rc=t; ud(pos); } } void newroot(int pos) { access(pos); splay(pos); laz[pos]^=1; } void lk(int x,int y) { newroot(x); newroot(y);// fa[y]=x; num[x]^=sum[y]; ud(x); } void del(int x,int y) { newroot(x); access(y); splay(y); son[y][0]=fa[x]=0; ud(y); } int main() { srand(1031); read(n); int op,x,y; ll r; read(n); read(m); For(i,1,n-1) { read(x); read(y); lk(x,y); } For(i,1,m) { read(op); if(op==1) { read(x); read(y); del(x,y); read(x); read(y); lk(x,y); } else if(op==2) { read(x); read(y); node[++tot]=Node(x,y,r=rand()*rand()); newroot(x); num[x]^=r; ud(x); newroot(y); num[y]^=r; ud(y); now^=r; } else if(op==3) { read(r); x=node[r].x; y=node[r].y; r=node[r].num; newroot(x); num[x]^=r; ud(x); newroot(y); num[y]^=r; ud(y); now^=r; } else { read(x); read(y); newroot(x); newroot(y); printf(sum[x]==now?"YES ":"NO "); } } return 0; } /* 0 5 7 1 2 1 3 2 4 1 5 2 1 5 1 1 5 2 5 4 2 5 2 1 4 4 2 5 3 1 4 2 4 */
bzoj4573大森林
感觉是一道非常有意思的题
当时看到这道题也觉得这种题肯定是把所有树的共同点一起维护了,然后对于不同的树的查询修改些地方
对于每次换生长节点就建一个虚点(权为0)
然后生长就在上一个建的虚点上长实点(权为1)
先把虚点串起来,考虑离线后,按照区间从左到右做
一个虚点会在一段时间有用,就把他连到对于实点的下面
否则他的父亲就是上一个虚点。
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define db double #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) #define lc son[pos][0] #define rc son[pos][1] const int maxn=3e5+7; int n,m,ans[maxn]; int son[maxn][2],fa[maxn],sum[maxn],num[maxn]; int L[maxn],R[maxn],id[maxn],tid,tot,last; char cc; ll ff; template<typename T>void read(T& aa) { aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } struct Ask{ int pos,t,x,y; Ask(){} Ask(int pos,int t,int x,int y):pos(pos),t(t),x(x),y(y){} bool operator < (const Ask& b) const{return pos==b.pos? t<b.t:pos<b.pos;} }ask[2*maxn]; int totask,totq; void ud(int pos){sum[pos]=sum[lc]+sum[rc]+num[pos];} int newnode(int x) {num[++tot]=x; ud(tot); return tot;} bool isroot(int pos) {return son[fa[pos]][0]!=pos&&son[fa[pos]][1]!=pos;} void rotate(int pos) { int x,y,p; y=fa[x=fa[pos]]; p=son[x][1]==pos; if(!isroot(x)) son[y][son[y][1]==x]=pos; fa[pos]=y; son[x][p]=son[pos][!p]; fa[son[pos][!p]]=x; son[pos][!p]=x; fa[x]=pos; ud(x); ud(pos); } void splay(int pos) { for(int x,y;!isroot(pos);rotate(pos)) { y=fa[x=fa[pos]]; if(!isroot(x)) (son[x][1]==pos^son[y][1]==x)? rotate(pos):rotate(x); } } int access(int pos) { int t=0; for(;pos;pos=fa[t=pos]) { splay(pos); rc=t; ud(pos); } return t; } void lk(int x,int y) { splay(x); fa[x]=y; } void cut(int pos) { access(pos); splay(pos); fa[lc]=0; lc=0; ud(pos); } int Yth(int x,int y) { int rs=0,lca; access(x); splay(x); rs+=sum[x]; lca=access(y); splay(y); rs+=sum[y]; access(lca); splay(lca); rs-=2*sum[lca]; return rs; } int main() { read(n); read(m); id[++tid]=newnode(1);L[1]=1;R[1]=n; newnode(0);lk(2,1);last=2; int op,l,r,x; For(i,1,m) { read(op); if(op==0) { read(l); read(r); id[++tid]=newnode(1); L[tot]=l; R[tot]=r; lk(tot,last); } else if(op==1) { read(l); read(r); read(x); l=max(l,L[id[x]]); r=min(r,R[id[x]]); if(l>r) continue; lk(newnode(0),last); ask[++totask]=Ask(l,i-m,tot,id[x]); ask[++totask]=Ask(r+1,i-m,tot,last); last=tot; } else { read(x); read(l); read(r); ask[++totask]=Ask(x,++totq,id[l],id[r]); } } sort(ask+1,ask+totask+1); For(i,1,totask) { if(ask[i].t<=0) { cut(ask[i].x); lk(ask[i].x,ask[i].y); } else ans[ask[i].t]=Yth(ask[i].x,ask[i].y); } For(i,1,totq) printf("%d ",ans[i]); return 0; } /* 5 5 0 1 5 1 2 4 2 0 1 4 2 1 1 3 2 2 1 3 */
bzoj3669魔法森林
没有删除操作的动态MST问题
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define db double #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) #define lc son[pos][0] #define rc son[pos][1] const int maxn=2e5+7,INF=0x3f3f3f3f; int n,m,f[maxn],ans=INF; int num[maxn],maxnum[maxn],son[maxn][2],fa[maxn],laz[maxn],tot; char cc; ll ff; template<typename T>void read(T& aa) { aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } int find(int x) {return x==f[x]? x:f[x]=find(f[x]);} struct Node{ int x,y,a,b; bool operator < (const Node& r) const{return a==r.a? b<r.b:a<r.a;} }node[maxn]; void ud(int pos){ maxnum[pos]=num[maxnum[lc]]>num[maxnum[rc]]? maxnum[lc]:maxnum[rc]; if(num[pos]>num[maxnum[pos]]) maxnum[pos]=pos; } bool isroot(int pos) {return son[fa[pos]][0]!=pos&&son[fa[pos]][1]!=pos;} int newnode(int r) {num[++tot]=r; ud(tot); return tot;} void pd(int pos) { if(!laz[pos]) return ; swap(lc,rc); if(lc) laz[lc]^=1; if(rc) laz[rc]^=1; laz[pos]=0; } void rotate(int pos) { int x,y,p; y=fa[x=fa[pos]]; p=son[x][1]==pos; if(!isroot(x)) son[y][son[y][1]==x]=pos; fa[pos]=y; son[x][p]=son[pos][!p]; fa[son[pos][!p]]=x; son[pos][!p]=x; fa[x]=pos; ud(x); ud(pos); } int zz[maxn]; void splay(int pos) { int x,y,t=0,p; for(p=pos;!isroot(p);p=fa[p]) zz[++t]=p; zz[++t]=p; while(t) pd(zz[t--]); for(;!isroot(pos);rotate(pos)) { y=fa[x=fa[pos]]; if(!isroot(x)) (son[x][1]==pos^son[y][1]==x)? rotate(pos):rotate(x); } } void access(int pos) { for(int t=0;pos;pos=fa[t=pos]) { splay(pos); rc=t; ud(pos); } } void newroot(int pos) { access(pos); splay(pos); laz[pos]^=1; } void lk(int x,int y,int r) { int p=newnode(r); newroot(x); newroot(y); fa[x]=fa[y]=p; } void cut(int pos) { newroot(pos); splay(pos); fa[lc]=fa[rc]=0; } int Yth(int x,int y) { if(find(x)!=find(y)) return -1; newroot(x); access(y); splay(y); return maxnum[y]; } int main() { read(n); read(m); For(i,1,n) newnode(0),f[i]=i; For(i,1,m) { read(node[i].x); read(node[i].y); read(node[i].a); read(node[i].b); } sort(node+1,node+m+1); int x,y,pos; For(i,1,m) { x=node[i].x; y=node[i].y; if(find(x)!=find(y)) { f[find(x)]=find(y); lk(x,y,node[i].b); } else { pos=Yth(x,y); if(num[pos]>node[i].b) { cut(pos); lk(x,y,node[i].b); } } pos=Yth(1,n); if(~pos) ans=min(ans,num[pos]+node[i].a); } if(ans!=INF) printf("%d",ans); else printf("-1"); return 0; } /* 4 5 1 2 19 1 2 3 8 12 2 4 12 15 1 3 17 8 3 4 1 17 */
bzoj3595方伯伯的OJ
只要不卡常,什么都好,map+set+splay
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> #include<map> #include<set> using namespace std; #define ll long long #define db double #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) #define lc son[pos][0] #define rc son[pos][1] const int maxn=6e5+7; const ll Bs=1e7; int n,m,tot,root; int L[maxn],R[maxn],sum[maxn],num[maxn],fa[maxn],son[maxn][2]; map<int,int> G,H; struct Node{ int l,r,id; Node(int l,int r,int id):l(l),r(r),id(id){} bool operator < (const Node& b) const{return l==b.l? r<b.r : l<b.l;} }; set<Node> P; set<Node>::iterator it; char cc; ll ff; template<typename T>void read(T& aa) { aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } ll pr(ll x,ll y) {return x*Bs+y;} ll fi(ll x){return x/Bs;} ll se(ll x){return x%Bs;} void ud(int pos) {num[pos]=R[pos]-L[pos]+1; sum[pos]=num[pos]+sum[lc]+sum[rc];} int newnode(int l,int r,int f) { fa[++tot]=f; L[tot]=l; R[tot]=r; P.insert(Node(l,r,tot)); ud(tot); if(f) ud(f); return tot; } void del(int pos) { Node o=Node(L[pos],R[pos],pos); it=P.lower_bound(o); P.erase(it); lc=rc=fa[pos]=0; num[pos]=sum[pos]=0; } int get_id(int x) { Node o=Node(x,x+1,0); it=P.lower_bound(o); if(it->l>x) --it; return it->id; } void rotate(int pos) { int x,y,p; y=fa[x=fa[pos]]; p=son[x][1]==pos; if(y) son[y][son[y][1]==x]=pos; if(x==root) root=pos; fa[pos]=y; son[x][p]=son[pos][!p]; fa[son[pos][!p]]=x; son[pos][!p]=x; fa[x]=pos; ud(x); ud(pos); } void splay(int pos) { for(int x,y;fa[pos];rotate(pos)) { y=fa[x=fa[pos]]; if(y) (son[x][1]==pos^son[y][1]==x)? rotate(pos):rotate(x); } } int merge(int x,int y) { if((ll)x*y==0) return x+y; splay(x); splay(y); while(son[x][1]) x=son[x][1]; splay(x); son[x][1]=y; fa[y]=x; ud(y); ud(x); return x; } ll split(int pos,int x) { splay(pos); int ld=lc,rd=rc,l,r; del(pos); l=newnode(L[pos],x,0); r=newnode(x+1,R[pos],0); son[l][0]=ld; fa[ld]=l; son[r][1]=rd; fa[rd]=r; ud(l); ud(r); root=merge(l,r); return pr(l,r); } void cut(int pos) { splay(pos); fa[lc]=fa[rc]=0; root=merge(lc,rc); lc=rc=0; } int sep(int pos,int x) { if(L[pos]==x&&R[pos]==x) return pos; if(L[pos]!=x) pos=se(split(pos,x-1)); if(R[pos]!=x) pos=fi(split(pos,x)); return pos; } int qrank(int x) { int pos=get_id(x); splay(pos); return sum[lc]+(x-L[pos]+1); } int qnum(int pos,int &x) { if(x>sum[lc]&&x<=sum[lc]+num[pos]) return x-=sum[lc],pos; if(x<=sum[lc]) return qnum(lc,x); x-=sum[lc]+num[pos]; return qnum(rc,x); } int main() { read(n); read(m); newnode(1,n,0); root=1; son[1][0]=newnode(1,0,1); son[1][1]=newnode(n+1,n,1); int op,x,y,pos,p,last=0; For(i,1,m) { read(op); read(x); x-=last; if(op==1) { read(y); y-=last; G[y]=G[x]? G[x]:x; G[x]=0; H[G[y]]=y; last=qrank(G[y]); } else { if(op!=4&&G[x]) x=G[x]; if(op==2) { pos=get_id(x); last=qrank(x); pos=sep(pos,x); cut(pos); cut(2); root=merge(pos,root); root=merge(2,pos); } else if(op==3) { pos=get_id(x); last=qrank(x); pos=sep(pos,x); cut(pos); cut(3); root=merge(root,pos); root=merge(root,3); } else { pos=qnum(root,x); x=x+L[pos]-1; last=H[x]? H[x]:x; } } printf("%d ",last); } return 0; } /* 10 10 1 2 11 3 13 2 5 3 7 2 8 2 10 2 11 3 14 2 18 4 9 */