题意:
给出一颗树,点上有初始权值,有四种操作;
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