[Luogu P3384] [Template] Light and heavy chain split

[Template] Light and heavy chain split

Title link: luogu P3384

General idea

There is a tree, point weights, and you need to maintain some operations.
Add a value or query sum to the point weights of the points in the path between the two points.
Add a value or query sum to the point weights of the points in the subtree corresponding to a point.

The root is given, and the output sum is modulo a given number.

Ideas

This question is also a template question for tree chain division. I wrote one before, so I won’t write about how to do tree chain division.
——>Click here to watch<——

But this question has a newer thing than that one, which is to operate on the subtree of a point.
What about this?
We consider the position of the points in the subtree in the line segment tree, by observing the process of building the line segment tree. Then you are labeling by dfs, the point of that subtree must be a continuous segment, and the beginning is the root node of this subtree, which is the point.
Then it is an interval in the line segment tree, set the root node of this subtree as root rootr o o t , the size (number of nodes) issizeroot size_{root}sizeroot, Then point ii in the treeThe position of i in the line segment tree isdyi dy_id yi, The segment tree for its interval is dyroot ∼ dyroot + sizeroot − 1 dy_{root}\sim dy_{root}+size_{root}-1d yrootd yroot+sizeroot1

That's it.
Remember to take the modulo.

Code

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

using namespace std;

struct node {
    
    
	int to, nxt;
}e[200001];
int n, x, y, z, le[100001], KK, tot, q, root, mo;
int number[100001], top[100001], tree_pl[100001], normal_pl[400001];
int fa[100001], num[100001], deg[100001], son[100001];
long long sum[400001], Sum, lazy[400001];
int op, size[100001];

void add(int x, int y) {
    
    
	e[++KK] = (node){
    
    y, le[x]}; le[x] = KK;
}

void dfs1(int now, int father) {
    
    
	fa[now] = father;
	deg[now] = deg[father] + 1;
	size[now] = 1;
	for (int i = le[now]; i; i = e[i].nxt)
		if (father != e[i].to) {
    
    
			dfs1(e[i].to, now);
			size[now] += size[e[i].to];
			if (size[e[i].to] > size[son[now]])
				son[now] = e[i].to;
		}
}

void dfs2(int now, int father) {
    
    
	if (son[now]) {
    
    
		tree_pl[son[now]] = ++tot;
		top[son[now]] = top[now];
		normal_pl[tree_pl[son[now]]] = son[now];
		dfs2(son[now], now);
	}
	
	for (int i = le[now]; i; i = e[i].nxt)
		if (e[i].to != father && e[i].to != son[now]) {
    
    
			tree_pl[e[i].to] = ++tot;
			top[e[i].to] = e[i].to;
			normal_pl[tree_pl[e[i].to]] = e[i].to;
			dfs2(e[i].to, now);
		}
}

void up(int now) {
    
    
	sum[now] = sum[now << 1] + sum[now << 1 | 1];
	sum[now] %= mo;
}

void down(int now, int l, int r) {
    
    
	int mid = (l + r) >> 1;
	sum[now << 1] += lazy[now] * (mid - l + 1) % mo;
	sum[now << 1] %= mo;
	sum[now << 1 | 1] += lazy[now] * (r - (mid + 1) + 1) % mo;
	sum[now << 1 | 1] %= mo;
	lazy[now << 1] += lazy[now];
	lazy[now << 1] %= mo;
	lazy[now << 1 | 1] += lazy[now];
	lazy[now << 1 | 1] %= mo;
	lazy[now] = 0;
}

void build(int now, int l, int r) {
    
    
	if (l == r) {
    
    
		sum[now] = number[normal_pl[l]] % mo;
		return ;
	}
	int mid = (l + r) >> 1;
	build(now << 1, l, mid);
	build(now << 1 | 1, mid + 1, r);
	up(now);
}

void add_num(int now, int l, int r, int L, int R, int add__num) {
    
    
	if (l > R || r < L) return ;
	if (l >= L && r <= R) {
    
    
		sum[now] = (sum[now] + ((r - l + 1) * add__num) % mo) % mo;
		if (l != r) lazy[now] += add__num;
		return ;
	}
	down(now, l, r);
	int mid = (l + r) >> 1;
	if (L <= mid) add_num(now << 1, l, mid, L, R, add__num);
	if (mid + 1 <= R)add_num(now << 1 | 1, mid + 1, r, L, R, add__num);
	up(now);
}

void query(int now, int l, int r, int L, int R) {
    
    
	if (r < L || l > R) return ;
	if (l >= L && r <= R) {
    
    
		Sum += sum[now];
		Sum %= mo;
		return ;
	}
	down(now, l, r);
	int mid = (l + r) >> 1;
	if (L <= mid) query(now << 1, l, mid, L, R);
	if (mid + 1 <= R) query(now << 1 | 1, mid + 1, r, L, R);
}

void ask(int x, int y) {
    
    
	while (top[x] != top[y]) {
    
    
		if (deg[top[x]] < deg[top[y]]) {
    
    
			swap(x, y);
		}
		query(1, 1, tot, tree_pl[top[x]], tree_pl[x]);
		x = fa[top[x]];
	}
	if (deg[x] > deg[y]) swap(x, y);
	query(1, 1, tot, tree_pl[x], tree_pl[y]);
}

void insert(int x, int y, int z) {
    
    
	while (top[x] != top[y]) {
    
    
		if (deg[top[x]] < deg[top[y]]) {
    
    
			swap(x, y);
		}
		add_num(1, 1, tot, tree_pl[top[x]], tree_pl[x], z);
		x = fa[top[x]];
	}
	if (deg[x] > deg[y]) swap(x, y);
	add_num(1, 1, tot, tree_pl[x], tree_pl[y], z);
}

int main() {
    
    
	scanf("%d %d %d %d", &n, &q, &root, &mo);
	for (int i = 1; i <= n; i++) scanf("%d", &number[i]);
	for (int i = 1; i < n; i++) {
    
    
		scanf("%d %d", &x, &y);
		add(x, y);
		add(y, x);
	}
	
	dfs1(root, 0);
	tot = 1;
	top[root] = root;
	tree_pl[root] = 1;
	normal_pl[1] = root;
	dfs2(root, 0);
	
	build(1, 1, tot);
	
	for (int i = 1; i <= q; i++) {
    
    
		scanf("%d", &op);
		
		if (op == 1) {
    
    
			scanf("%d %d %d", &x, &y, &z);
			insert(x, y, z);
		}
		else if (op == 2) {
    
    
			scanf("%d %d", &x, &y);
			Sum = 0;
			ask(x, y);
			printf("%lld\n", Sum);
		}
		else if (op == 3) {
    
    
			scanf("%d %d", &x, &y);
			add_num(1, 1, tot, tree_pl[x], tree_pl[x] + size[x] - 1, y);
			//某个点对应子树在线段树中的位置=它在线段树中的位置~它的位置+它子树的节点个数-1
			//下面同理
		}
		else if (op == 4) {
    
    
			scanf("%d", &x);
			Sum = 0;
			query(1, 1, tot, tree_pl[x], tree_pl[x] + size[x] - 1);
			printf("%lld\n", Sum);
		}
	}
	
	return 0;
}

Guess you like

Origin blog.csdn.net/weixin_43346722/article/details/113919324