3.CF343D Water Tree 树剖+线段树区间覆盖
线段树维护树上覆盖问题,树剖序列化维护序列覆盖。
洛谷传送门:CF343D Water Tree - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
CF传送门:D. Water Tree (codeforces.com)
题目分析
给出一棵以 为根节点的 个节点的有根树。每个点有一个权值,初始为 。
- 次操作。操作有种:
- 将点和其子树上的所有节点的权值改为。
- 将点到的路径上的所有节点的权值改为。
- 询问点
树上问题序列化,树剖一下,线段树维护区间推平操作
- 对应线段树区间:
- 对应线段树区间:沿重链向上跳到根节点,至多log个区间,第一个区间:
- 直接树上单点查询即可
Code
#include <bits/stdc++.h>
#pragma gcc optimize("O2")
#pragma g++ optimize("O2")
#define int long long
#define endl '\n'
using namespace std;
const int N = 2e5 + 10, MOD = 1e9 + 7;
vector<int> g[N];
int a[N];
int pfa[N], dep[N], siz[N], son[N], top[N], dfn[N], rnk[N], ind;
void dfs1(int u, int fa){
pfa[u] = fa, dep[u] = dep[fa] + 1, siz[u] = 1;
for(auto &v : g[u]){
if(v == fa) continue;
dfs1(v, u);
siz[u] += siz[v];
if(siz[v] > siz[son[u]]) son[u] = v;
}
}
void dfs2(int u, int tp){
dfn[u] = ++ind, rnk[ind] = u, top[u] = tp;
if(!son[u]) return;
dfs2(son[u], tp);
for(auto & v: g[u]){
if(v == pfa[u] || v == son[u]) continue;
dfs2(v, v);
}
}
namespace SegTree{
#define ls rt << 1
#define rs rt << 1 | 1
#define lson ls, l,
#define rson rs, mid + 1,
int tree[N << 2], lazy[N << 2];
inline void push_down(int rt, int ll, int lr, int rl, int rr){
if(!lazy[rt]) return;
if(ll == lr) tree[ls] += (dep[rnk[ll]] & 1 ? 1 : -1) * lazy[rt];
if(rl == rr) tree[rs] += (dep[rnk[rr]] & 1 ? 1 : -1) * lazy[rt];
lazy[ls] += lazy[rt], lazy[rs] += lazy[rt];
lazy[rt] = 0;
}
void build(int rt, int l, int r){
lazy[rt] = 0;
if(l == r){
tree[rt] = a[rnk[l]];
return;
}
int mid = l + r >> 1;
build(lson), build(rson);
}
void update(int rt, int l, int r, int L, int R, int val){
if(l >= L && r <= R){
if(l == r) tree[rt] += (dep[rnk[l]] & 1 ? 1 : -1) * val;
else lazy[rt] += val;
return;
}
int mid = l + r >> 1;
push_down(rt, l, mid, mid + 1, r);
if(mid >= L) update(lson, L, R, val);
if(mid < R) update(rson, L, R, val);
}
int query(int rt, int l, int r, int pos){
if(l == r) return tree[rt];
int mid = l + r >> 1;
push_down(rt, l, mid, mid + 1, r);
if(mid >= pos) return query(lson, pos);
else return query(rson, pos);
}
}
#define SEGRG 1, 1,
inline void solve(){
int n, m = 0; cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= n - 1; i++){
int u = 0, v = 0; cin >> u >> v;
g[u].emplace_back(v);
g[v].emplace_back(u);
}
dfs1(1, 0), dfs2(1, 1);
SegTree::build(1, 1, n);
while(m--){
int op, v; cin >> op >> v;
if(op == 1){
int x = 0; cin >> x;
if(!(dep[v] & 1)) x *= -1;
SegTree::update(SEGRG, dfn[v], dfn[v] + siz[v] - 1, x);
} else {
cout << SegTree::query(SEGRG, dfn[v]) << endl;
}
}
}
signed main(){
ios_base::sync_with_stdio(false), cin.tie(0);
cout << fixed << setprecision(12);
int t = 1; //cin >> t;
while(t--) solve();
return 0;
}