好像很少有关于top数组性质的博客。
for(int i=top[x];fa[i];i=top[fa[i]])
可以遍历所有子树中含有x节点的重链链头节点(或叶子节点),由于重链不超过log(n)个,所以这个循环复杂度是O(logN)的。
设i是重链链头节点,f是i的父节点,则i是f的轻儿子。
所以,如果有操作:对于x节点,他的所有儿子均加上不同的值,且这个值只与儿子节点自身和提供的值有关,那么,可以只更新x节点的重儿子,在x节点加上标记,查询的时候加上答案即可。
D. Tree Queries
Hanh is a famous biologist. He loves growing trees and doing experiments on his own garden.
One day, he got a tree consisting of n vertices. Vertices are numbered from 1 to n. A tree with n vertices is an undirected connected graph with n−1 edges. Initially, Hanh sets the value of every vertex to 0.
Now, Hanh performs q operations, each is either of the following types:
Type 1. Hanh selects a vertex v and an integer d. Then he chooses some vertex r uniformly at random, lists all vertices u such that the path from r to u passes through v. Hanh then increases the value of all such vertices u by d.
Type 2. Hanh selects a vertex v and calculates the expected value of v.
Since Hanh is good at biology but not math, he needs your help on these operations.
Input
The first line contains two integers n and q (1≤n,q≤150000) — the number of vertices on Hanh’s tree and the number of operations he performs.
Each of the next n−1 lines contains two integers u and v (1≤u,v≤n), denoting that there is an edge connecting two vertices u and v. It is guaranteed that these n−1 edges form a tree.
Each of the last q lines describes an operation in either formats:
1
v
d
(
1
≤
v
≤
n
,
0
≤
d
≤
1
0
7
)
1 v d (1≤v≤n,0≤d≤10^7)
1vd(1≤v≤n,0≤d≤107), representing a first-type operation.
2
v
(
1
≤
v
≤
n
)
2 v (1≤v≤n)
2v(1≤v≤n), representing a second-type operation.
It is guaranteed that there is at least one query of the second type.
Output
For each operation of the second type, write the expected value on a single line.
Let M=998244353, it can be shown that the expected value can be expressed as an irreducible fraction pq, where p and q are integers and q≢0(modM). Output the integer equal to p⋅q−1modM. In other words, output such an integer x that 0≤x<M and x⋅q≡p(modM).
Example
input
5 12
1 2
1 3
2 4
2 5
1 1 1
2 1
2 2
2 3
2 4
2 5
1 2 2
2 1
2 2
2 3
2 4
2 5
output
1
199648871
399297742
199648871
199648871
598946614
199648873
2
2
2
分析r相对于v的位置容易得如何更新答案,对给定节点v,需要对整棵树操作一次和子树v操作一次以及对v的每个子节点u,减去d*siz[son[u]]*inv,这样做是O(N)的复杂度,只能过11个点,当然,也可以按子树大小分块,复杂度降到了
O
(
N
)
O(\sqrt N)
O(N),但是好像码量有些大。
所以,可以只更新v节点的重儿子,轻儿子的更新标记放置在v节点上,因为轻儿子一定是重链头结点或叶子节点,所以查询的时候减去多余的答案即可。
#include<bits/stdc++.h>
using namespace std;
char buf[1<<20],*_=buf,*__=buf;
#define gc() (_==__&&(__=(_=buf)+fread(buf,1,1<<20,stdin),_==__)?EOF:*_++)
#define TT template<class T>inline
TT bool read(T &x){
x=0;char c=gc();bool f=0;
while(c<48||c>57){if(c==EOF)return 0;f^=(c=='-'),c=gc();}
while(47<c&&c<58)x=(x<<3)+(x<<1)+(c^48),c=gc();
if(f)x=-x;return 1;
}
TT bool read(T&a,T&b){return read(a)&&read(b);}
TT bool read(T&a,T&b,T&c){return read(a)&&read(b)&&read(c);}
typedef long long ll;
const ll MAXN=1e5+8,mod=1e9+8,inf=0x3f3f3f3f;
#define lowbit(x) (x&(-x))
#define Max(a,b) if(b>a)a=b
#define Min(a,b) if(b<a)a=b
int n;
struct E{int y,nt;}e[MAXN<<1];
int head[MAXN],cnt;
inline void add(int x,int y){
e[++cnt].y=y;
e[cnt].nt=head[x];
head[x]=cnt;
}
int dep[MAXN],siz[MAXN],fa[MAXN],son[MAXN];
void dfs1(int x){
siz[x]=1,dep[x]=dep[fa[x]]+1;
for(int i=head[x];i;i=e[i].nt){
int y=e[i].y;
if(siz[y])continue;
fa[y]=x;
dfs1(y);
siz[x]+=siz[y];
if(!son[x]||siz[son[x]]<siz[y])son[x]=y;
}
}
int id[MAXN],top[MAXN],idcnt;
ll d[MAXN];
void dfs2(int x,int tp){
id[x]=++idcnt;
top[x]=tp;
if(son[x])dfs2(son[x],tp);
for(int i=head[x];i;i=e[i].nt){
int y=e[i].y;
if(id[y])continue;
dfs2(y,y);
}
}
inline void presum_add(int p,ll v){
while(p<=n){
(d[p]+=v)%=mod;
p+=lowbit(p);
}
}
inline ll ask(int p){
ll res=0;
while(p){
(res+=d[p])%=mod;
p-=lowbit(p);
}return res;
}
inline void subtree_add(const int x,const ll v){
presum_add(id[x],v);
presum_add(id[x]+siz[x],mod-v);
}
ll qpow(ll x,ll k){
ll res=1;
while(k){
if(k&1)res=res*x%mod;
x=x*x%mod;k>>=1;
}return res;
}
ll lazy[MAXN];
int main() {
int q;
read(n,q);
for(int i=1,x,y;i<n;++i){
read(x,y);
add(x,y);
add(y,x);
}
dfs1(1);
dfs2(1,1);
int op,x;
ll inv=qpow(n,mod-2),val;
while(q--){
read(op,x);
if(op==1){
read(val);
(lazy[x]+=val)%=mod;
subtree_add(x,(n-siz[x])*val%mod);
subtree_add(1,siz[x]*val%mod);
if(!son[x])continue;
subtree_add(son[x],mod-siz[son[x]]*val%mod);
}
else{
ll res=ask(id[x]);
for(int i=top[x];fa[i];i=top[fa[i]]){
(res+=mod-siz[i]*lazy[fa[i]]%mod)%=mod;
}
printf("%I64d\n",res*inv%mod);
}
}
return 0;
}