题意:
给出一颗树,点上有初始权值,有四种操作;
1.加一条边;
2.删一条边;
3.一条路径上的点都加一个权值;
4.查询一条路径上任取两个点的路径上期望权值和;
题解:
本题是2752的升级版,一些公式之类的东西参照上题;
到了树上之后,实际上本质的公式是没有变的,只有一些外在的形式改变了;
因为Splay维护的是树上的重链,那么结点维护的就是链上的答案等东西;
转移一样但是有几点注意;
这里选取的两个点可以相等,所以总方案数是n*(n+1)/2;
换根反转区间时,L[x]和R[x]要相应改变(其实就是交换);
别忘了输出-1的特殊情况;
然后用力码一码就可以过了;
代码:
#include<stdio.h> #include<string.h> #include<algorithm> #define N 51000 #define which(x) (ch[fa[x]][1]==x) using namespace std; typedef unsigned long long ll; ll fa[N],ch[N][2],size[N],sum[N],val[N],ans[N],L[N],R[N],cov[N]; bool rt[N],rev[N]; void Pushup(ll x) { size[x]=size[ch[x][0]]+size[ch[x][1]]+1; sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+val[x]; ans[x]=ans[ch[x][0]]+ans[ch[x][1]]+val[x]*(size[ch[x][0]]+1)*(size[ch[x][1]]+1) +L[ch[x][0]]*(size[ch[x][1]]+1)+R[ch[x][1]]*(size[ch[x][0]]+1); L[x]=L[ch[x][0]]+val[x]*(size[ch[x][0]]+1)+L[ch[x][1]]+sum[ch[x][1]]*(size[ch[x][0]]+1); R[x]=R[ch[x][1]]+val[x]*(size[ch[x][1]]+1)+R[ch[x][0]]+sum[ch[x][0]]*(size[ch[x][1]]+1); } void update(ll x,ll v) { cov[x]+=v; val[x]+=v; sum[x]+=v*size[x]; L[x]+=size[x]*(size[x]+1)/2*v; R[x]+=size[x]*(size[x]+1)/2*v; ans[x]+=size[x]*(size[x]+1)*(size[x]+2)/6*v; } void reverse(ll x) { swap(ch[x][0],ch[x][1]); swap(L[x],R[x]); rev[x]^=1; } void Pushdown(ll x) { if(rev[x]) { reverse(ch[x][0]); reverse(ch[x][1]); rev[x]=0; } if(cov[x]) { update(ch[x][0],cov[x]); update(ch[x][1],cov[x]); cov[x]=0; } } void down(ll x) { if(!rt[x]) down(fa[x]); Pushdown(x); } void Rotate(ll x) { ll f=fa[x]; bool k=which(x); if(rt[f]) rt[f]=0,rt[x]=1; else ch[fa[f]][which(f)]=x; ch[f][k]=ch[x][!k]; ch[x][!k]=f; fa[ch[f][k]]=f; fa[x]=fa[f]; fa[f]=x; Pushup(f); Pushup(x); } void Splay(ll x) { down(x); while(!rt[x]) { ll f=fa[x]; if(rt[f]) { Rotate(x); return ; } if(which(x)^which(f)) Rotate(x); else Rotate(f); Rotate(x); } } void access(ll x) { ll y=0; while(x) { Splay(x); rt[ch[x][1]]=1,rt[y]=0; ch[x][1]=y; Pushup(x); y=x,x=fa[x]; } } void Mtr(ll x) { access(x); Splay(x); reverse(x); } bool judge(ll x,ll y) { Mtr(x); access(y); Splay(x); while(!rt[y]) y=fa[y]; return x==y; } void Link(ll x,ll y) { Mtr(x); fa[x]=y; } void Cut(ll x,ll y) { Mtr(x); access(y); Splay(x); if(ch[x][1]==y&&!size[ch[y][0]]) { ch[x][1]=fa[y]=0; rt[y]=1; Pushup(x); } } void add(ll x,ll y,ll v) { Mtr(x); access(y); Splay(x); update(x,v); } ll query(ll x,ll y) { Mtr(x); access(y); Splay(x); return ans[x]; } ll gcd(ll a,ll b) { ll t=a%b; while(t) { a=b,b=t; t=a%b; } return b; } int main() { ll n,m,i,j,k,op,x,y,v; scanf("%llu%llu",&n,&m); for(i=1;i<=n;i++) { scanf("%llu",&v); val[i]=sum[i]=v; L[i]=R[i]=ans[i]=v; size[i]=rt[i]=1; } for(i=1;i<n;i++) { scanf("%llu%llu",&x,&y); Link(x,y); } for(i=1;i<=m;i++) { scanf("%llu",&op); switch(op) { case 1: scanf("%llu%llu",&x,&y); Cut(x,y); break; case 2: scanf("%llu%llu",&x,&y); if(!judge(x,y)) Link(x,y); break; case 3: scanf("%llu%llu%llu",&x,&y,&v); if(judge(x,y)) add(x,y,v); break; case 4: scanf("%llu%llu",&x,&y); if(!judge(x,y)) puts("-1"); else { ll u=query(x,y),d=size[x]*(size[x]+1)/2; ll g=gcd(u,d); printf("%llu/%llu\n",u/g,d/g); } } } return 0; }
原文地址:http://blog.csdn.net/ww140142/article/details/47760323