CF1254D Tree Queries
CF1254D Tree Queries
好题一道。至少让我一种新的套路(bush)。
首先我们来考虑操作 1,我们发现当我们选好一个点
很容易得到,每次修改后,对于每一颗子树,其中所有点的期望都会增加
首先我们可以直接树剖暴力搞,拿线段树之类的维护区间加单点查。然鹅,这样的做法菊花图复杂度直接起飞(因为每次都要把
第一个优化就是我们可以考虑搞树上差分,这样就可以免除区间修改;但是这样还是无法做到快速修改。然后我就贺翻题解学了个新套路:只对重儿子进行修改,然后每次查询把链顶贡献加上即可。
具体怎么干捏?就是,假如我们现在进行操作
对于每次询问,因为如果是轻链,则不会被修改,也就是说,会少一个差分,我们只需要每次把这个差分加上即可。我们发现,链顶处就是轻重儿子分开的地方,所以我们要加上链顶的贡献。
代码:
#include<bits/stdc++.h> using namespace std; const int N = 150050, mod = 998244353; inline int read(){ int x = 0, f = 1; char ch = getchar(); while(ch<'0' || ch>'9'){if(ch == '-') f = -1; ch = getchar();} while(ch>='0'&&ch<='9'){x = x*10+ch-48; ch = getchar();} return x * f; } inline int fpow(int a, int b){ int ret = 1; while(b){ if(b & 1){ ret = (1ll*ret*a)%mod; } b>>=1; a = (1ll*a*a)%mod; } return ret; } int n, Q, p; int inv; //———————————— struct node{ int nxt, to; }edge[N<<1]; int head[N], tot; void add(int u, int v){ edge[++tot].nxt = head[u]; edge[tot].to = v; head[u] = tot; } int dfn[N], dep[N], fa[N], son[N], siz[N], totd; void dfs1(int u, int fath){ fa[u] = fath; siz[u] = 1; dep[u] = dep[fath]+1; for(int i = head[u]; i; i = edge[i].nxt){ int v = edge[i].to; if(v == fath) continue; dfs1(v, u); siz[u]+=siz[v]; if(siz[son[u]]<siz[v]) son[u] = v; } } int top[N]; void dfs2(int u, int Top){ top[u] = Top; dfn[u] = ++totd; if(!son[u]) return; dfs2(son[u], Top); for(int i = head[u]; i; i = edge[i].nxt){ int v = edge[i].to; if(!dfn[v]) dfs2(v, v); } } //———————————————— int val[N]; int tc[N]; inline int lowbit(int x){ return x&(-x); } void insert(int pos, int val){ for(int i = pos; i<=n; i+=lowbit(i)){ tc[i] = (1ll*tc[i]+val)%mod; } } inline int query(int pos){ int ret = 0; for(int i = pos; i; i-=lowbit(i)){ ret = (1ll*ret+tc[i])%mod; } return ret; } int main(){ n = read(), Q = read(); inv = fpow(n, mod-2); for(int i = 1; i<n; ++i){ int u = read(), v = read(); add(u, v); add(v, u); } dfs1(1, 0); dfs2(1, 1); while(Q--){ int op = read(); if(op == 1){ int v = read(), d = read(); (val[v]+=d)%=mod; if(v ^ 1){ insert(dfn[v], 1ll*d*(n-siz[v])%mod); } insert(1, 1ll*d*siz[v]%mod); if(son[v]){ insert(dfn[son[v]], 1ll*d*(mod-siz[son[v]])%mod); } } else{ int v = read(); int ans = 0; while(top[v] ^ 1){ ans = (((ans+query(dfn[v]))%mod-query(dfn[top[v]]-1))%mod+1ll*val[fa[top[v]]]*(mod-siz[top[v]])%mod)%mod;//求差分前缀和+补差价 v = fa[top[v]]; } (ans+=query(dfn[v]))%=mod; ans = (ans+mod)%mod; printf("%d\n", 1ll*ans*inv%mod); } } system("pause"); return 0; }