Description
树上链翻转,链加,查询链上的和/max/min
树链剖分套treap,修改查询可以用类似线段树的写法,翻转可以利用分裂合并和翻转标记实现,时间复杂度O(nlog2n)
实测除了翻转之外的操作常数较小,翻转由于需要把整条链拆出来再合并回去,稍慢一些
#include<cstdio> #include<algorithm> typedef long long i64; const int N=50007; int _(){ int x;scanf("%d",&x);return x; } i64 _a; void maxs(i64&a,i64 b){if(a<b)a=b;} void mins(i64&a,i64 b){if(a>b)a=b;} struct node{ node*lc,*rc; int sz,rnd,rv; i64 a,v,s,mx,mn; void _rev(){ if(!this)return; rv^=1; std::swap(lc,rc); } void _add(i64 x){ if(!this)return; a+=x;v+=x; mx+=x;mn+=x; s+=x*sz; } void dn(){ if(rv){ lc->_rev(); rc->_rev(); rv=0; } if(a){ lc->_add(a); rc->_add(a); a=0; } } void up(){ sz=1;s=v; mx=mn=v; if(lc){ sz+=lc->sz; s+=lc->s; maxs(mx,lc->mx); mins(mn,lc->mn); } if(rc){ sz+=rc->sz; s+=rc->s; maxs(mx,rc->mx); mins(mn,rc->mn); } } void sp(int k,node*&l,node*&r){ if(!this){l=r=0;return;} int ls=lc?lc->sz:0; dn(); if(k<=ls)lc->sp(k,l,lc),r=this; else rc->sp(k-ls-1,rc,r),l=this; up(); } node*mg(node*a){ if(!a)return this; if(!this)return a; if(rnd>a->rnd){ dn(); rc=rc->mg(a); up(); return this; } a->dn(); a->lc=mg(a->lc); a->up(); return a; } #define DEF(A,B,C) \ void A(int l,int r){\if(!this||r<=0||l>=sz)return;\ if(l<=0&&r>=sz){B;return;}\ int ls=lc?lc->sz:0;\ dn();\ if(l<=ls&&r>ls)C;\ if(l<ls)lc->A(l,r);\ if(r>ls+1)rc->A(l-ls-1,r-ls-1);\ up();\ } DEF(add,_add(_a),v+=_a) DEF(gmx,maxs(_a,mx),maxs(_a,v)) DEF(gmn,mins(_a,mn),mins(_a,v)) DEF(sum,_a+=s,_a+=v) #undef DEF }ns[N],*rt[N]; int es[N*2],enx[N*2],e0[N],ep=2; int fa[N],sz[N],son[N],dep[N],top[N]; void f1(int w,int pa){ dep[w]=dep[fa[w]=pa]+1; sz[w]=1; for(int i=e0[w];i;i=enx[i]){ int u=es[i]; if(u!=pa){ f1(u,w); sz[w]+=sz[u]; if(sz[u]>sz[son[w]])son[w]=u; } } } void f2(int w,int tp){ top[w]=tp; rt[tp]=rt[tp]->mg(ns+w); if(son[w])f2(son[w],tp); for(int i=e0[w];i;i=enx[i]){ int u=es[i]; if(u!=fa[w]&&u!=son[w])f2(u,u); } } #define DEF(A) \ void A(int x,int y){\ int a=top[x],b=top[y];\ while(a!=b){\ if(dep[a]<dep[b])std::swap(a,b),std::swap(x,y);\ rt[a]->A(0,dep[x]-dep[a]+1);\ x=fa[a],a=top[x];\ }\ if(dep[x]>dep[y])std::swap(x,y);\ rt[a]->A(dep[x]-dep[a],dep[y]-dep[a]+1);\ } DEF(add) DEF(gmx) DEF(gmn) DEF(sum) #undef DEF node*s1[40][3],*s2[40][3]; int sz1[40],w1[40],sz2[40],w2[40]; void rev(int x,int y){ if(x==y)return; int a=top[x],b=top[y],p1=0,p2=0; while(a!=b){ if(dep[a]>dep[b]){ s1[p1][0]=0; rt[a]->sp(dep[x]-dep[a]+1,s1[p1][1],s1[p1][2]); w1[p1]=a; sz1[p1]=s1[p1][1]->sz; ++p1; x=fa[a],a=top[x]; }else{ s2[p2][0]=0; rt[b]->sp(dep[y]-dep[b]+1,s2[p2][1],s2[p2][2]); w2[p2]=b; sz2[p2]=s2[p2][1]->sz; ++p2; y=fa[b],b=top[y]; } } if(dep[x]>dep[y]){ rt[a]->sp(dep[y]-dep[a],s1[p1][0],s1[p1][1]); s1[p1][1]->sp(dep[x]-dep[y]+1,s1[p1][1],s1[p1][2]); w1[p1]=a; sz1[p1]=s1[p1][1]->sz; ++p1; }else{ rt[a]->sp(dep[x]-dep[a],s2[p2][0],s2[p2][1]); s2[p2][1]->sp(dep[y]-dep[x]+1,s2[p2][1],s2[p2][2]); w2[p2]=a; sz2[p2]=s2[p2][1]->sz; ++p2; } node*p=0; for(int i=0;i<p1;++i)p=s1[i][1]->mg(p); p->_rev(); for(int i=p2-1;i>=0;--i)p=p->mg(s2[i][1]); for(int i=0;i<p1;++i)p->sp(p->sz-sz1[i],p,s1[i][1]); p->_rev(); for(int i=p2-1;i>=0;--i)p->sp(sz2[i],s2[i][1],p); for(int i=0;i<p1;++i)rt[w1[i]]=s1[i][0]->mg(s1[i][1])->mg(s1[i][2]); for(int i=0;i<p2;++i)rt[w2[i]]=s2[i][0]->mg(s2[i][1])->mg(s2[i][2]); } int n,m,r; char op[16]; int main(){ scanf("%d%d%d",&n,&m,&r); for(int i=1;i<=n;++i)ns[i].rnd=rand()|1,ns[i].sz=1; for(int i=1,a,b;i<n;++i){ scanf("%d%d",&a,&b); es[ep]=b;enx[ep]=e0[a];e0[a]=ep++; es[ep]=a;enx[ep]=e0[b];e0[b]=ep++; } f1(1,0); f2(1,1); while(m--){ int x,y,z; scanf("%s%d%d",op,&x,&y); if(op[2]=='c'){ scanf("%d",&z); _a=z; add(x,y); }else if(op[2]=='m'){ _a=0; sum(x,y); printf("%lld\n",_a); }else if(op[2]=='j'){ _a=-(1ll<<60); gmx(x,y); printf("%lld\n",_a); }else if(op[2]=='n'){ _a=1ll<<60; gmn(x,y); printf("%lld\n",_a); }else{ rev(x,y); } } return 0; }