题目链接https://codeforces.com/contest/1254/problem/D
题意
给出一棵树,每个点都有权值,初始都为0,有两个操作
- 给出 v , d v,d v,d,等概率随机一个点 r r r,对于所有的点 u u u, u u u到 r r r的路径上经过点 v v v。对于所有的这些点 u u u权值加上 d d d。
- 求点 v v v的权值期望
1 < = n , q < = 150000 1<=n,q<=150000 1<=n,q<=150000
题解
考虑第二个询问点
u
u
u,计算每个1操作点
v
v
v的贡献。
如果
l
c
a
(
u
,
v
)
!
=
v
lca(u,v)!=v
lca(u,v)!=v,点
v
v
v对答案的贡献是
s
i
z
e
[
v
]
n
∗
d
[
v
]
\frac{size[v]}{n}*d[v]
nsize[v]∗d[v]
否则,答案的贡献是
n
−
s
i
z
e
[
w
]
n
∗
d
[
v
]
\frac{n-size[w]}{n}*d[v]
nn−size[w]∗d[v],其中
w
w
w是点
v
v
v的儿子的子树中包含点
u
u
u的节点。
对于第一种情况我们只需要记一个 t o t tot tot累加即可,对于第二种情况如果暴力枚举父亲节点肯定会超时。对于这个我们可以采用树剖来进行优化,每一次进行1操作,对于重儿子子树内的点直接区间更新,用线段树或者树状数组维护都可以。等到查询的时候一直往上跳 t o p top top,把没更新过的答案更新一下即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
const ll N=4e5+7;
const ll mod=998244353;
int n,q;
ll invn;
struct Edge{
int v,nxt;
}e[N];
int p[N],edn;
void add(int u,int v){
e[++edn]=(Edge){v,p[u]};p[u]=edn;
e[++edn]=(Edge){u,p[v]};p[v]=edn;
}
ll qpow(ll a,ll b){
ll res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;b>>=1;
}
return res;
}
int fa[N],le[N],ri[N],son[N],sz[N],top[N],idx;
void dfs(int u){
sz[u]=1;
le[u]=++idx;
for(int i=p[u];~i;i=e[i].nxt){
int v=e[i].v;
if(v==fa[u]) continue;
fa[v]=u;
dfs(v);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]]) son[u]=v;
}
ri[u]=idx;
}
void bdfs(int u,int k){
top[u]=k;
if(son[u]) bdfs(son[u],k);
for(int i=p[u];~i;i=e[i].nxt){
int v=e[i].v;
if(v==fa[u]||v==son[u]) continue;
bdfs(v,v);
}
}
ll b[N],c[N];
int lb(int x){return x&(-x);}
void upd(int x,int val){
while(x<N){
c[x]=(c[x]+val+mod)%mod;
x+=lb(x);
}
}
ll ask(int x){
ll res=0;
while(x){
res=(res+c[x]+mod)%mod;
x-=lb(x);
}
return res;
}
int main(){
memset(p,-1,sizeof(p));edn=-1;
scanf("%d%d",&n,&q);
invn=qpow(n,mod-2);
for(int i=1,u,v;i<n;i++){
scanf("%d%d",&u,&v);
add(u,v);
}
dfs(1);
bdfs(1,1);
ll tot=0;
for(int i=1,o,v,d;i<=q;i++){
scanf("%d",&o);
if(o==1){
scanf("%d%d",&v,&d);
tot=(tot+sz[v]*invn%mod*d%mod);
b[v]=(b[v]+d)%mod;
if(son[v]){
ll val=-sz[v]*invn%mod*d%mod+(n-sz[son[v]])*invn%mod*d%mod;
upd(le[son[v]],val);
upd(ri[son[v]]+1,-val);
}
}
else{
scanf("%d",&v);
ll ans=(tot-sz[v]*invn%mod*b[v]%mod+mod)%mod+b[v];
ans=(ans+ask(le[v]))%mod;
while(1){
v=top[v];
if(v==1) break;
ans=(ans-sz[fa[v]]*invn%mod*b[fa[v]]%mod+(n-sz[v])*invn%mod*b[fa[v]]%mod+mod)%mod;
v=fa[v];
}
printf("%lld\n",ans);
}
}
}