只能说这题很妙。
给出一棵树,树上有权值,现在你对一个结点加\(x\),那么他的孩子结点会加\(-x\),依次类推。
操作有单点加,单点查询。
实际上可以把树按照深度划分为奇和偶。定义奇数的加,偶数的减。
如果说深度为奇数,那么就把它的所有孩子结点都加\(x\),如果说深度为偶数,那么就把它的所有孩子结点都加\(-x\)。
查询时,同样这样,如果深度是奇数,那么就把答案乘1,否则乘-1。
对于深度为偶数的,加的时候是负数,查询的时候再乘以负号,答案不变。如果有贡献是由深度为奇数的加上的,那么加的一定是正数,最后乘负号,答案不变。
同理,对于深度为奇数的,加的时候是正数,查询的时候是正数。如果有贡献来自深度为偶数的,那么加的值肯定是负数。
相当于变成了线段树区间加操作和单点查询操作了。
树上线段树操作,可以用树链剖分,但是大材小用了,就直接利用dfs序+线段树即可。
#include <bits/stdc++.h>
#define ll long long
#define CASE int Kase = 0; cin >> Kase; for(int kase = 1; kase <= Kase; kase++)
using namespace std;
template<typename T = long long> inline T read() {
T s = 0, f = 1; char ch = getchar();
while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
while(isdigit(ch)) {s = (s << 3) + (s << 1) + ch - 48; ch = getchar();}
return s * f;
}
const int N = 2e5 + 5, M = 1e6 + 5, MOD = 1e9 + 7, CM = 998244353, INF = 0x3f3f3f3f;
struct Edge {
int to, next;
}e[M << 1];
int head[N], tot;
void add(int u, int v){
e[++tot].to = v;
e[tot].next = head[u];
head[u] = tot;
}
int a[N];
struct SegTree{
struct Node{
int l, r;
int val, lazy;
#define l(p) tree[p].l
#define r(p) tree[p].r
#define lson (p << 1)
#define rson (p << 1 | 1)
#define val(p) tree[p].val
#define lazy(p) tree[p].lazy
} tree[N << 2];
void pushup(int p){
val(p) = val(lson) + val(rson);
}
void pushdown(int p){
if(lazy(p)) {
lazy(lson) += lazy(p);
lazy(rson) += lazy(p);
val(lson) += (r(lson) - l(lson) + 1) * lazy(p);
val(rson) += (r(rson) - l(rson) + 1) * lazy(p);
lazy(p) = 0;
}
}
void build(int p, int l, int r){
l(p) = l, r(p) = r;
lazy(p) = 0, val(p) = 0;
if(l(p) == r(p)) {
return;
}
int mid = (l + r) >> 1;
build(lson, l, mid); build(rson, mid + 1, r);
pushup(p);
}
void Change(int p, int l, int r, int x) {
if(l <= l(p) && r(p) <= r) {
lazy(p) += x;
val(p) += (r(p) - l(p) + 1) * x;
return;
}
pushdown(p);
int mid = (l(p) + r(p)) >> 1;
if(l <= mid) Change(lson, l, r, x);
if(r > mid) Change(rson, l, r, x);
pushup(p);
}
int Query(int p, int x) {
if(l(p) == r(p)) return val(p);
pushdown(p);
int mid = (l(p) + r(p)) >> 1;
if(x <= mid) return Query(lson, x);
else return Query(rson, x);
}
} seg;
int dep[N], l[N], r[N], id;
void dfs(int u, int fath){
dep[u] = dep[fath] + 1; l[u] = ++id;
for(int i = head[u]; i; i = e[i].next) {
int v = e[i].to;
if(v == fath) continue;
dfs(v, u);
}
r[u] = id;
}
void subtask1() {
int x = read(), val = read();
seg.Change(1, l[x], r[x], dep[x] & 1 ? val : -val);
}
void subtask2() {
int x = read();
printf("%d\n", a[x] + seg.Query(1, l[x]) * (dep[x] & 1 ? 1 : -1));
}
void solve(int kase){
int n = read(), m = read();
for(int i = 1; i <= n; i++) a[i] = read();
for(int i = 1; i < n; i++) {
int u = read(), v = read();
add(u, v); add(v, u);
}
dfs(1, 0);
seg.build(1, 1, n);
for(int i = 1; i <= m; i++) {
int op = read();
if(op == 1) subtask1();
if(op == 2) subtask2();
}
}
const bool DUO = 0;
int main(){
clock_t start, finish; double totaltime; start = clock();
if(DUO) {CASE solve(kase);} else solve(1);
finish = clock();
#ifdef ONLINE_JUDGE
return 0;
#endif
printf("\nTime: %lfms\n", (double)(finish - start) / CLOCKS_PER_SEC * 1000);
return 0;
}