CF383C Propagating tree
题面
题目描述
Iahub非常喜欢树木。最近,他发现了一棵有趣的树,名为传播树。该树由从 \(1\) 到 \(N\) 编号的 \(N\) 个节点组成,每个节点 \(i\) 都有一个初始值 \(ai\) 。树的根节点为 \(1\)。
该树具有一个特殊的属性:节点 \(i\) 的值增加 \(val\) 时, \(i\) 的所有子节点将会减少 \(val\) 。请注意,此时 \(i\) 的所有子节点的子节点还将增加 \(val\) ,以此类推。
本题有 \(M\) 个询问,分为两种:
1 x val 将节点 \(x\) 的值增加 \(val\)
2 x 查询节点 \(x\) 的当前值
输入格式
第一行包含两个整数 \(N,M\) ,如题目描述所说
第二行包含 \(N\) 个整数,\(a1,a2,...,an\)
接下来 \(N−1\) 行有两个整数 \(u,v\) ,代表两者之间存在一条边
接下来的\(M\)行中的每行都包含上述格式的查询
输出格式
对于每个类型为 \(2\) 的查询(查询节点 \(x\) 的值),按照输入中给出的顺序在单独的行上回答查询
输入样例
5 5
1 2 1 1 2
1 2
1 3
2 4
2 5
1 2 3
1 1 2
2 1
2 2
2 4
输出样例
3
3
0
数据范围与提示
\(1≤n,m≤200,000\)
\(1≤ai,val≤1000\)
\(1≤vi,ui\),\(x≤n\)
题解
想到线段树+dfs序。
但是由于有+和-,还是断层的。难道是bfs序??????
发现各层之间互不干扰,所以可以建两颗线段树分别维护基数层和偶数层。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 200005;
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<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
inline void write(int x) {
if (x < 0) {
x = ~(x - 1);
putchar('-');
}
if (x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
int n, m;
int v[maxn];
vector <int> g[maxn];
int ll[2*maxn], rr[2*maxn], dfn[2*maxn], clk;
int dep[maxn];
struct two_tree{
int s[maxn * 4], a[maxn];
int tag[4*maxn];
void push_up(int x){
s[x] = s[2*x] + s[2*x+1];
}
void push_down(int x, int len){
tag[2*x] += tag[x];
tag[2*x+1] += tag[x];
s[2*x] += tag[x] * (len - len / 2);
s[2*x+1] += tag[x] * (len / 2);
tag[x] = 0;
}
void build(int l, int r, int x){
if(l == r){
s[x] = a[l];
return ;
}
int mid = (l+r)/2;
build(l, mid, 2*x);
build(mid+1, r, 2*x+1);
push_up(x);
}
void add(int dl, int dr, int l, int r, int pls, int x){
if(l > dr or r < dl) return ;
if(l >= dl and r <= dr){
s[x] += pls * (r - l + 1);
if(l != r) tag[x] += pls;
return ;
}
int mid = (l + r) / 2;
push_down(x, r - l + 1);
add(dl, dr, l, mid, pls, 2*x);
add(dl, dr, mid+1, r, pls, 2*x+1);
push_up(x);
}
int query(int dl, int dr, int l, int r, int x){
if(l > dr or r < dl) return 0;
if(l >= dl and r <= dr){
return s[x];
}
int mid = (l+r)/2;
int ans = 0;
push_down(x, r - l + 1);
if(dl <= mid) ans += query(dl, dr, l, mid, 2*x);
if(dr > mid) ans += query(dl, dr, mid+1, r, 2*x+1);
push_up(x);
return ans;
}
};
two_tree A, B;
void dfs(int x, int fa){
dep[x] = dep[fa] + 1;
dfn[x] = ++clk;
ll[x] = rr[x] = dfn[x];
A.a[dfn[x]] = B.a[dfn[x]] = v[x];
for(int i = 0; i < g[x].size(); i++){
if(g[x][i] == fa) continue;
dfs(g[x][i], x);
ll[x] = min(ll[x], ll[g[x][i]]);
rr[x] = max(rr[x], rr[g[x][i]]);
}
return ;
}
signed main(){
n = read(), m = read();
for(int i = 1; i <= n; i++){
v[i] = read();
}
for(int i = 1; i < n; i++){
int u = read(), vv = read();
// cin>>u>>vv;
g[u].push_back(vv);
g[vv].push_back(u);
}
dfs(1, 0);
A.build(1, n, 1), B.build(1, n, 1);
while (m--)
{
int op = read();
// cin>>op;
if(op == 2){
int x = read();
// cin>>x;
if(dep[x] % 2){
write(A.query(dfn[x], dfn[x], 1, clk, 1));
puts("");
}else{
write(B.query(dfn[x], dfn[x], 1, clk, 1));
puts("");
// cout<<<<endl;
}
}else{
int x = read(), val = read();
// cin>>x>>val;
if(dep[x] % 2){
A.add(ll[x], rr[x], 1, clk, val, 1);
B.add(ll[x], rr[x], 1, clk, -val, 1);
}else{
A.add(ll[x], rr[x], 1, clk, -val, 1);
B.add(ll[x], rr[x], 1, clk, val, 1);
}
// add(ll[x], rr[x], 1, clk, 1, val);
}
}
// system("PAUSE");
return 0;
}