思路:
第二遍dfs时记录end[x]为在结点序列中以x为根的子树最后访问的节点,写个线段树标记下传即可。与值有关的数据注意long long
#include<cstdio> #include<iostream> #include<vector> #include<cmath> #include<string> using namespace std; const int maxn = 100010; inline void qread(int &x){ x = 0; register int ch = getchar(), flag = 0; while(ch < ‘0‘ || ch > ‘9‘) { if(ch == ‘-‘) flag = 1; ch = getchar(); } while(ch >= ‘0‘ && ch <= ‘9‘) x = 10 * x + ch - 48, ch = getchar(); if(flag) x = -x; } int n, m, rt = 1; int val[maxn]; int head[maxn]; int go[maxn << 1]; int nxt[maxn << 1]; int f[maxn]; int deep[maxn]; int size[maxn]; int son[maxn]; int top[maxn]; int seg[maxn]; int rev[maxn]; int end[maxn]; long long cov[maxn << 2]; long long sum[maxn << 2]; long long SUM; inline void init(){ qread(n); qread(m); for(int i=1; i<=n; ++i) qread(val[i]); for(register int i=1; i<n; ++i){ register int x, y; qread(x), qread(y); go[i] = y; go[i + n] = x; nxt[i] = head[x]; head[x] = i; nxt[i + n] = head[y]; head[y] = i + n; } deep[rt] = 1; seg[0] = seg[1] = rev[1] = top[1] = 1; } void dfs1(int x){ size[x] = 1; for(register int i = head[x]; i; i = nxt[i]) if(!deep[go[i]]){ f[go[i]] = x; deep[go[i]] = deep[x] + 1; dfs1(go[i]); size[x] += size[go[i]]; if(size[go[i]] > size[son[x]]) son[x] = go[i]; } } void dfs2(int x){ end[x] = x; if(son[x]){ seg[son[x]] = ++seg[0]; top[son[x]] = top[x]; rev[seg[0]] = son[x]; dfs2(son[x]); end[x] = end[son[x]]; } for(register int i = head[x]; i; i = nxt[i]){ if(!top[go[i]]){ seg[go[i]] = ++seg[0]; rev[seg[0]] = go[i]; top[go[i]] = go[i]; dfs2(go[i]); end[x] = end[go[i]]; } } } inline void pushdown(int x, int t){ cov[x << 1] += cov[x]; cov[x << 1 | 1] += cov[x]; sum[x << 1] += cov[x] * ((t + 1) >> 1); sum[x << 1 | 1] += cov[x] * (t >> 1); cov[x] = 0; } void segbuild(int l, int r, int x){ if(l==r){ sum[x] = val[rev[l]]; return ; } int mid = (l + r) >> 1; segbuild(l, mid, x << 1); segbuild(mid + 1, r, x << 1 | 1); sum[x] = sum[x << 1] + sum[x << 1 | 1]; } void segadd(int l, int r, int L, int R, long long v, int x){ if(L <= l && R >= r){ cov[x] += v; sum[x] += v * (r - l + 1); return ; } pushdown(x, r - l + 1); int mid = (l + r) >> 1; if(mid >= L) segadd(l, mid, L, R, v, x << 1); if(mid < R) segadd(mid + 1, r, L, R, v, x << 1 | 1); sum[x] = sum[x << 1] + sum[x << 1 | 1]; } void segquery(int l, int r, int L, int R, int x){ if(L <= l && R >= r){ SUM += sum[x]; return ; } pushdown(x, r - l + 1); int mid = (l + r) >> 1; if(mid >= L) segquery(l, mid, L, R, x << 1); if(mid < R) segquery(mid + 1, r, L, R, x << 1 | 1); } void treeask(int x, int y){ int fx = top[x], fy = top[y]; while(fx != fy){ if(deep[fx] < deep[fy]) swap(x, y), swap(fx, fy); segquery(1, seg[0], seg[fx], seg[x], 1); x = f[fx]; fx = top[x]; } if(deep[x] > deep[y]) swap(x, y); segquery(1, seg[0], seg[x], seg[y], 1); } int main(void){ freopen("data6.in.txt", "r", stdin); freopen("data6my.txt", "w", stdout); init(); dfs1(rt); dfs2(rt); segbuild(1, seg[0], 1); while(m--){ int op; qread(op); if(op == 1){ int x, a; qread(x), qread(a); segadd(1, seg[0], seg[x], seg[x], a, 1); } else if(op == 2){ int x, a; qread(x), qread(a); segadd(1, seg[0], seg[x], seg[end[x]], a, 1); } else{ int x; qread(x); SUM = 0; treeask(rt, x); printf("%lld\n", SUM); } } }
原文地址:https://www.cnblogs.com/junk-yao-blog/p/9480761.html
时间: 2024-11-08 07:12:25