BZOJ 3091: 城市旅行 LCT
维护 $\sum_{}v[i]\times dep[i]$ 与 $\sum_{} v[i]\times dep[i]^2$
其中 $dep[i]$ 表示 $i$ 点在该点所在 $LCT$ 的 $splay$ 中的中序遍历序.
然后正着维护一个,反着维护一个就行了.
#include <cstdio> #include <cstring> #include <string> #include <map> #include <algorithm> #define N 50005 #define ll long long #define siz size #define ts tag #define lson s[x].ch[0] #define rson s[x].ch[1] #define get(x) (s[s[x].f].ch[1]==x) #define Isr(x) (!(s[s[x].f].ch[0]==x||s[s[x].f].ch[1]==x)) using namespace std; ll sqr(ll x) { return x*x; } ll calc1(ll x) { return x*(x+1ll)/2; } ll calc2(ll x) { return x*(x+1ll)*(2ll*x+1ll)/6; } ll gcd(ll a,ll b) { return b?gcd(b,a%b):a; } namespace IO { void setIO(string s) { string in=s+".in"; string out=s+".out"; freopen(in.c_str(),"r",stdin); freopen(out.c_str(),"w",stdout); } }; int sta[N]; map<int,int>con[N]; struct node { int ch[2],rev,f; ll s0[2],s1[2],s2[2],tag,v,size; }s[N]; void Pushup(int x) { s[x].size=s[lson].size+s[rson].size+1; s[x].s0[0]=s[lson].s0[0]+s[rson].s0[0]+s[x].v; s[x].s1[0]=s[lson].s1[0]+s[rson].s1[0]+(s[rson].s0[0]+s[x].v)*(s[lson].size+1); s[x].s2[0]=s[s[x].ch[0]].s2[0]+s[s[x].ch[1]].s2[0]+(s[s[x].ch[1]].s0[0]+s[x].v)*(s[s[x].ch[0]].size+1)*(s[s[x].ch[0]].size+1)+2ll*s[s[x].ch[1]].s1[0]*(s[s[x].ch[0]].size+1); s[x].s0[1]=s[lson].s0[1]+s[rson].s0[1]+s[x].v; s[x].s1[1]=s[rson].s1[1]+s[lson].s1[1]+(s[lson].s0[1]+s[x].v)*(s[rson].size+1); s[x].s2[1]=s[s[x].ch[1]].s2[1]+s[s[x].ch[0]].s2[1]+(s[s[x].ch[0]].s0[1]+s[x].v)*(s[s[x].ch[1]].size+1)*(s[s[x].ch[1]].size+1)+2ll*s[s[x].ch[0]].s1[1]*(s[s[x].ch[1]].size+1); } void Up_tag(int x,ll v) { s[x].v+=v; s[x].tag+=v; s[x].s0[0]+=s[x].size*v; s[x].s0[1]+=s[x].size*v; s[x].s1[0]+=calc1(s[x].size)*v; s[x].s1[1]+=calc1(s[x].size)*v; s[x].s2[0]+=calc2(s[x].size)*v; s[x].s2[1]+=calc2(s[x].size)*v; } void Up_rev(int x) { s[x].rev^=1; swap(lson,rson); swap(s[x].s0[0],s[x].s0[1]); swap(s[x].s1[0],s[x].s1[1]),swap(s[x].s2[0],s[x].s2[1]); } void Pushdown(int x) { if(s[x].tag) { if(lson) Up_tag(lson,s[x].tag); if(rson) Up_tag(rson,s[x].tag); s[x].tag=0; } if(s[x].rev) { if(lson) Up_rev(lson); if(rson) Up_rev(rson); s[x].rev=0; } } void rotate(int x) { int old=s[x].f,fold=s[old].f,which=get(x); if(!Isr(old)) s[fold].ch[s[fold].ch[1]==old]=x; s[old].ch[which]=s[x].ch[which^1]; if(s[old].ch[which]) s[s[old].ch[which]].f=old; s[x].ch[which^1]=old,s[old].f=x,s[x].f=fold; Pushup(old),Pushup(x); } void Splay(int x) { int v=0,u=x,fa; for(sta[++v]=u;!Isr(u);u=s[u].f) sta[++v]=s[u].f; for(;v;--v) Pushdown(sta[v]); for(u=s[u].f;(fa=s[x].f)!=u;rotate(x)) { if(s[fa].f!=u) rotate(get(fa)==get(x)?fa:x); } } void Access(int x) { for(int y=0;x;y=x,x=s[x].f) { Splay(x); rson=y; Pushup(x); } } void Make_Root(int x) { Access(x); Splay(x); Up_rev(x); } void Link_Edge(int x,int y) { Access(x),Splay(x); Make_Root(y); s[y].f=x; } void Cut_Edge(int x,int y) { Make_Root(x),Access(y),Splay(y); if(!s[x].ch[1]&&s[y].ch[0]==x) s[y].ch[0]=s[x].f=0; Pushup(y); } void Split(int x,int y) { Make_Root(x),Access(y),Splay(y); } int Find_Root(int x) { while(s[x].f) x=s[x].f; return x; } int main() { // IO::setIO("input"); int i,j,n,m; scanf("%d%d",&n,&m); for(i=1;i<=n;++i) scanf("%lld",&s[i].v),Pushup(i); for(i=1;i<n;++i) { int x,y; scanf("%d%d",&x,&y); Link_Edge(x,y); con[x][y]=con[y][x]=1; } for(i=1;i<=m;++i) { int op,x,y,z; scanf("%d",&op); if(op==1) { scanf("%d%d",&x,&y); if(!con[x][y]) continue; else { Cut_Edge(x,y); con[x][y]=con[y][x]=0; } } if(op==2) { scanf("%d%d",&x,&y); if(Find_Root(x)==Find_Root(y)) continue; else { con[x][y]=con[y][x]=1; Link_Edge(x,y); } } if(op==3) { scanf("%d%d%d",&x,&y,&z); if(Find_Root(x)!=Find_Root(y)) continue; Split(x,y); Up_tag(y,(ll)z); } if(op==4) { scanf("%d%d",&x,&y); if(Find_Root(x)!=Find_Root(y)) printf("-1\n"); else { Split(x,y); ll dn=s[y].size*(s[y].size+1)/2; ll up=(s[y].size+1ll)*s[y].s1[0]-s[y].s2[0]; ll g=gcd(up,dn); printf("%lld/%lld\n",up/g,dn/g); } } } return 0; }