https://www.lydsy.com/JudgeOnline/problem.php?id=4034
有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
dfs序真是一个奥妙重重的东西
首先求出dfs序,操作1显然是一个单点修改,操作2显然是一个区间修改,我们看到我们要询问的事实上是一条链的和,我们就不能简单地进行单点修改和区间修改,事实上1到x的点在dfs序上可以视为一个栈,第一次出现是进栈,第二次出现时出栈,我们只要将进栈的点权为正,出栈的点权为负,线段树进行一波区间修改和区间查询即可。
#include <map> #include <set> #include <ctime> #include <cmath> #include <queue> #include <stack> #include <vector> #include <string> #include <cstdio> #include <cstdlib> #include <cstring> #include <sstream> #include <iostream> #include <algorithm> #include <functional> using namespace std; inline int read(){int now=0;register char c=getchar();for(;!isdigit(c);c=getchar()); for(;isdigit(c);now=now*10+c-'0',c=getchar());return now;} #define For(i, x, y) for(int i=x;i<=y;i++) #define _For(i, x, y) for(int i=x;i>=y;i--) #define Mem(f, x) memset(f,x,sizeof(f)) #define Sca(x) scanf("%d", &x) #define Sca2(x,y) scanf("%d%d",&x,&y) #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z) #define Scl(x) scanf("%lld",&x); #define Pri(x) printf("%d ", x) #define Prl(x) printf("%lld ",x); #define CLR(u) for(int i=0;i<=N;i++)u[i].clear(); #define LL long long #define ULL unsigned long long #define mp make_pair #define PII pair<int,int> #define PIL pair<int,long long> #define PLL pair<long long,long long> #define pb push_back #define fi first #define se second typedef vector<int> VI; const double eps = 1e-9; const int maxn = 4e5 + 10; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; int N,M,K; LL val[maxn]; struct Edge{ int to,next; }edge[maxn * 2]; int head[maxn],tot; void init(){Mem(head,-1); tot = 0;} void add(int u,int v){edge[tot].to = v;edge[tot].next = head[u];head[u] = tot++;} PII Index[maxn * 2]; PII pos[maxn]; int id = 0; void dfs(int t,int fa){ Index[++id].fi = t; Index[id].se = 1; pos[t].fi = id; for(int i = head[t]; ~i; i = edge[i].next){ int v = edge[i].to; if(v == fa) continue; dfs(v,t); } Index[++id].fi = t; Index[id].se = -1; pos[t].se = id; } struct Tree{ int l,r; int up,down; LL sum,lazy; }tree[maxn << 2]; void Pushup(int t){ tree[t].sum = tree[t << 1].sum + tree[t << 1 | 1].sum; } void Build(int t,int l,int r){ tree[t].l = l; tree[t].r = r; tree[t].up = tree[t].down = tree[t].lazy = 0; if(l == r){ if(Index[l].se == 1){ tree[t].sum = val[Index[l].fi]; tree[t].up++; }else{ tree[t].sum = -val[Index[l].fi]; tree[t].down++; } return ; } int m = (l + r) >> 1; Build(t << 1,l,m); Build(t << 1 | 1,m + 1,r); Pushup(t); tree[t].up = tree[t << 1].up + tree[t << 1 | 1].up; tree[t].down = tree[t << 1].down + tree[t << 1 | 1].down; } void Pushdown(int t){ if(tree[t].lazy){ tree[t << 1].sum += (tree[t << 1].up - tree[t << 1].down) * tree[t].lazy; tree[t << 1 | 1].sum += (tree[t << 1 | 1].up - tree[t << 1 | 1].down) * tree[t].lazy; tree[t << 1].lazy += tree[t].lazy; tree[t << 1 | 1].lazy += tree[t].lazy; tree[t].lazy = 0; } } void update(int t,int l,int r,LL a){ if(l <= tree[t].l && tree[t].r <= r){ tree[t].sum += (tree[t].up - tree[t].down) * a; tree[t].lazy += a; return; } Pushdown(t); int m = (tree[t].l + tree[t].r) >> 1; if(r <= m) update(t << 1,l,r,a); else if(l > m) update(t << 1 | 1,l,r,a); else{ update(t << 1,l,m,a); update(t << 1 | 1,m + 1,r,a); } Pushup(t); } LL query(int t,int l,int r){ if(l > r) return 0; if(l <= tree[t].l && tree[t].r <= r){ return tree[t].sum; } Pushdown(t); int m = (tree[t].l + tree[t].r) >> 1; if(r <= m) return query(t << 1,l,r); else if(l > m) return query(t << 1 | 1,l,r); else{ return query(t << 1,l,m) + query(t << 1 | 1,m + 1,r); } } int main() { Sca2(N,M); init(); For(i,1,N) Scl(val[i]); For(i,1,N - 1){ int u,v; Sca2(u,v); add(u,v); add(v,u);} int root = 1; id = 0; dfs(root,-1); Build(1,1,2 * N); while(M--){ int op = read(); if(op == 1){ int x; Sca(x); LL a; Scl(a); update(1,pos[x].fi,pos[x].fi,a); update(1,pos[x].se,pos[x].se,a); }else if(op == 2){ int x; Sca(x); LL a; Scl(a); update(1,pos[x].fi,pos[x].se,a); }else{ int x; Sca(x); Prl(query(1,1,pos[x].fi)); } } #ifdef VSCode system("pause"); #endif return 0; }