樹剖模板


題目描述

有一棵點數為 N 的樹,以點 1 為根,且樹點有邊權。然后有 M 個操作,分為三種:

操作 1 :把某個節點 x 的點權增加 a 。
操作 2 :把某個節點 x 為根的子樹中所有點的點權都增加 a 。
操作 3 :詢問某個節點 x 到根的路徑中所有點的點權和。
輸入格式

第一行包含兩個整數 N, M 。表示點數和操作數。
接下來一行 N 個整數,表示樹中節點的初始權值。
接下來 N-1 行每行兩個正整數 from, to , 表示該樹中存在一條邊 (from, to) 。
再接下來 M 行,每行分別表示一次操作。其中第一個數表示該操作的種類( 1-3 ) ,之后接這個操作的參數( x 或者 x a ) 。

輸出格式

對於每個詢問操作,輸出該詢問的答案。答案之間用換行隔開。

#include <cstdio>
#include <iostream>

#define int long long
#define lson(now) now << 1
#define rson(now) now << 1|1

const int maxx = 100010;
using namespace std;
int n, m, a[maxx], pre[maxx];

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 * 10 + ch - '0';ch = getchar();}
	return x * f;
}
//-----------------------------------------------------------------------------------------
struct tree{
	int lazy, sum, len;
}t[maxx << 2];
void push_up(int now)
{
	t[now].sum = t[lson(now)].sum + t[rson(now)].sum;
}
void build(int now, int l, int r)//建線段樹
{
	t[now].len = r - l + 1;//區間內元素的個數 
	if(l == r)
	{
		t[now].sum = a[pre[l]];
		return; 
	}
	int mid = (l + r) >> 1;
	build(lson(now), l, mid);
	build(rson(now), mid + 1, r);
	push_up(now);
} 

void push_down(int now)//下穿懶惰標記 
{
	if(t[now].lazy == 0)  return;
	t[lson(now)].sum += t[now].lazy * t[lson(now)].len;
	t[rson(now)].sum += t[now].lazy * t[rson(now)].len;
	t[lson(now)].lazy += t[now].lazy;
	t[rson(now)].lazy += t[now].lazy;
	t[now].lazy = 0;
}
void updata(int now, int val, int nl, int nr, int l, int r)//nl,nr為當前節點區間  l,r要查詢的區間, 
{
	if(nl >= l && nr <= r)//當前區間包含在要查詢的區間內 
	{
		t[now].sum += t[now].len * val;
		t[now].lazy += val;
		return; 
	} 
	push_down(now);
	int mid = (nl + nr) >> 1;
	if(l <= mid) updata(lson(now), val, nl, mid, l, r);
	if(r > mid) updata(rson(now), val, mid + 1, nr, l, r);
	push_up(now);
} 

int query(int now, int nl, int nr, int l, int r)
{
	if(l <= nl && r >= nr) return t[now].sum;
	push_down(now);
	int mid = (nl + nr) >> 1, ans = 0;
	if(l <= mid) ans += query(lson(now), nl, mid, l, r);
	if(r > mid) ans += query(rson(now), mid + 1, nr, l, r);
	return ans;
}

//------------------------------------------------------------
struct egde{
	int u, v, w, nxt;
}e[maxx << 1];
int head[maxx], js;
void add(int u, int v)
{
	e[++js].u = u;
	e[js].v = v;
	e[js].nxt = head[u];
	head[u] = js;
}
int fa[maxx], dep[maxx], size[maxx], son[maxx];//各個點的深度,父親,子樹大小,重兒子 
void dfs1(int u, int f, int d)//當前點,父親節點,深度 
{
	fa[u] = f;
	dep[u] = d;
	size[u] = 1;
	for(int i = head[u]; i; i = e[i].nxt)
	{
		int v = e[i].v;
		if(v != f)
		{
			dfs1(v, u, d+1);
			size[u] += size[v];
			if(!son[u]||size[son[u]] < size[v])//找重兒子 
			son[u] = v;
		}
	}
}
int top[maxx], pos[maxx], p;//記錄節點的鏈頂,記錄每個節點的位置  p位置 
void dfs2(int u, int tp)//找鏈  u 當前節點 tp 鏈頂    
{
	top[u] = tp;
	pos[u] = ++p; 
	pre[p] = u;
	if(!son[u]) return;//葉節點
	dfs2(son[u], tp);
	for(int i = head[u]; i; i = e[i].nxt) 
	{
		int v = e[i].v;
		if(v != son[u] && v != fa[u])
		dfs2(v, v);
	}
}
void change(int x, int y, int c)
{
	while(top[x] != top[y])
	{
		if(dep[top[x]] < dep[top[y]]) swap(x, y);
		updata(1, c, 1, n, pos[top[x]], pos[y]); 
		x = fa[top[x]];
	}
	if(dep[x] > dep[y]) swap(x, y);
	updata(1, c, 1, n, pos[x], pos[y]); 
}
int asksum(int x, int y)
{
	int ans = 0;
	while(top[x] != top[y])
	{
		if(dep[top[x]] < dep[top[y]]) swap(x, y);
		ans += query(1, 1, n, pos[top[x]], pos[x]);
		x = fa[top[x]];
	}
	if(dep[x] > dep[y]) swap(x, y);
	ans += query(1, 1, n, pos[x], pos[y]);
	return ans;
}

signed main()
{
    n = read(); m = read();
    for(int i = 1; i <= n; i++)
    a[i] = read();
    for(int i = 1; i < n; i++)
    {
    	int x = read(), y = read();
    	add(x, y);
    	add(y, x);
	}
	dfs1(1, 0, 1);
	dfs2(1, 1);
	build(1, 1, n);
	for(int i = 1; i <= m; i++)
	{
		int op = read();
		if(op == 1)
		{
			int x = read(), a = read();
			change(x, x, a);
		}
		if(op == 2)
		{
			int x = read(), a = read();
			updata(1, a, 1, n, pos[x], pos[x] + size[x] - 1);
		}
		if(op == 3)
		{
			int x = read();
			printf("%lld\n",asksum(x, 1));
		}
	}
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM