洛谷 P3178 [HAOI2015]树上操作

Description

洛谷传送门

Solution

树链剖分

树链剖分板子题,比板子还板子

关于树链剖分我就不多说了,如果有的话可以看我的博客 浅谈树链剖分

回归正题,我们发现题目只要求单点加,子树加,以及查询一点到根节点路径和。

单点加不就是区间加把左右端点改成那个点吗?

子树加不就是板子吗??

查询一点到根节点路径和不就是路径查询简化版吗???

综上所述,这道题是板子的板子

那么我们这道题就已经做完了,只需要把板子里多余的函数删掉就好啦。

别忘了开 \(long \ long\)

Code

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>

#define ll long long
#define N 500010
#define ls rt << 1
#define rs rt << 1 | 1
#define INF 0x3f3f3f3f

using namespace std;

struct node{
	ll v, nxt;
}edge[N << 1];
ll head[N], tot;
ll n, m;
ll w[N], tw[N];
ll dep[N], siz[N], fa[N], son[N];
ll top[N], id[N], cnt;
ll a[N << 2], lazy[N << 2];

inline ll read(){
	ll 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 << 3) + (x << 1) + ch - '0', ch = getchar();
	return f * x;
}

inline void add(ll x, ll y){
	edge[++tot] = (node){y, head[x]};
	head[x] = tot;
}

void dfs1(ll x, ll f){
	fa[x] = f;
	dep[x] = dep[f] + 1;
	siz[x] = 1;
	for(ll i = head[x]; i; i = edge[i].nxt){
		ll y = edge[i].v;
		if(y == f) continue;
		dfs1(y, x);
		siz[x] += siz[y];
		if(!son[x] || siz[y] > siz[son[x]])
			son[x] = y;
	}
}

void dfs2(ll x, ll topfa){
	top[x] = topfa;
	id[x] = ++cnt;
	tw[cnt] = w[x];
	if(!son[x]) return;
	dfs2(son[x], topfa);
	for(ll i = head[x]; i; i = edge[i].nxt){
		ll y = edge[i].v;
		if(y == fa[x] || y == son[x]) continue;
		dfs2(y, y);
	}
}

inline void pushup(ll rt){
	a[rt] = a[ls] + a[rs];
}

inline void pushdown(ll l, ll r, ll rt){
	if(lazy[rt]){
		ll mid = (l + r) >> 1;
		a[ls] += lazy[rt] * (mid - l + 1);
		a[rs] += lazy[rt] * (r - mid);
		lazy[ls] += lazy[rt];
		lazy[rs] += lazy[rt];
		lazy[rt] = 0;
	}
}

void build(ll l, ll r, ll rt){
	if(l == r){
		a[rt] = tw[l];
		return;
	}
	ll mid = (l + r) >> 1;
	build(l, mid, ls);
	build(mid + 1, r, rs);
	pushup(rt);
}

void update(ll L, ll R, ll k, ll l, ll r, ll rt){
	if(L <= l && r <= R){
		a[rt] += k * (r - l + 1);
		lazy[rt] += k;
		return;
	}
	pushdown(l, r, rt);
	ll mid = (l + r) >> 1;
	if(L <= mid) update(L, R, k, l, mid, ls);
	if(R > mid) update(L, R, k, mid + 1, r, rs);
	pushup(rt);
}

ll query(ll L, ll R, ll l, ll r, ll rt){
	if(L <= l && r <= R)
		return a[rt];
	pushdown(l, r, rt);
	ll mid = (l + r) >> 1;
	ll res = 0;
	if(L <= mid) res += query(L, R, l, mid, ls);
	if(R > mid) res += query(L, R, mid + 1, r, rs);
	return res;
}

void update_Son(ll x, ll k){
	update(id[x], id[x] + siz[x] - 1, k ,1, n, 1);
}

ll query_Range(ll x, ll y){
	ll res = 0;
	while(top[x] != top[y]){
		if(dep[top[x]] < dep[top[y]]) swap(x, y);
		res += query(id[top[x]], id[x], 1, n, 1);
		x = fa[top[x]];
	}
	if(dep[x] > dep[y]) swap(x, y);
	res += query(id[x], id[y], 1, n, 1);
	return res;
}

signed main(){
	n = read(), m =read();
	for(ll i = 1; i <= n; i++)
		w[i] = read();
	for(ll i = 1; i < n; i++){
		ll u, v;
		u = read(), v = read();
		add(u, v), add(v, u);
	}
	dfs1(1, 0);
	dfs2(1, 1);
	build(1, n, 1);
	while(m--){
		ll op, x, k;
		op = read();
		if(op == 1){
			x = read(), k = read();
			update(id[x], id[x], k, 1, n, 1);
		}else if(op == 2){
			x = read(), k = read();
			update_Son(x, k);
		}else{
			x = read();
			printf("%lld\n", query_Range(1, x));
		}
	}
	return 0;
}

End

posted @ 2021-08-06 14:24  xixike  阅读(28)  评论(0编辑  收藏  举报