BZOJ3307 rain tail (dynamic segment tree combined open point + tree + differential)

It is well known segment tree space complexity is O (N * 4), when N is large enough, easy to explode.
Dynamic open points that literally do not have to build the entire tree structure all out, only in the initial establishment of a node represents the re-establishment of this sub-tree node when the whole range, recursively need to access the sub-tree. Complete binary tree is no longer with twice the number of rules.
Dynamic prescription segment tree advantages: 1 may be incorporated to maintain the same range with the two segment tree. 2. save space, promote resource-saving society building
code implementation:

struct node {
	int l, r, s;//左右儿子编号和结点值
} e[N];
int build() {//新建一个结点,返回其编号
	tot++;
	e[tot].l = e[tot].r = e[tot].s = 0; 
	return tot;
}
void insert(int i, int l, int r, int pos, int k) {//单点修改
	if(l == r)  {
		e[i].s += k; e[i].num = pos;
		return ;
	}
	int mid = (l + r) >> 1;
	if(pos <= mid) {
		if(e[i].l == 0) e[i].l = build();//动态开点
		insert(e[i].l, l, mid, pos, k);
	} else {
		if(e[i].r == 0) e[i].r = build();//动态开点
		insert(e[i].r, mid + 1, r, pos, k);
	}
	update(i);
}

The combined segment tree:
there are two, one is merged into the new node, wherein a further node is deleted.
The latter as an example:
From the root of two, mark the current number of nodes with two variables, synchronize recursively traverse two trees.
1. When one is empty, return another.
2. When the value reaches the leaf node of the two nodes are added.

int merge(int p, int q, int l, int r) {
	if(!p) return q;
	if(!q) return p;//1
	if(l == r) {//2
		e[p].s += e[q].s; return p;
	}
	int mid = (l + r) >> 1;
	e[p].l = merge(e[p].l, e[q].l, l, mid);
	e[p].r = merge(e[p].r, e[q].r, mid + 1, r);
	update(p);
	return p;//只返回p,相当于删除q
}

BZOJ3307 rain Tail:
For this question, we build a segment tree for each tree node, the tree line represents the standard type of relief food to maintain its maximum.
Methods tree difference is read \ (x, y, z \ ) after, respectively, in \ (x, y \) on nodes \ (Z \) corresponding to the position +1, the \ (LCA (x, Y) \) node corresponds to position - 1 in the \ (Father (LCA (x, y)) \) node corresponds to position -1, thus ensuring that the number of one kind of a relief grain node is equal to all of its child nodes the number of this type of food and relief.
After modification, again DFS, the sub-tree tree line merge, query maximum.
Code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 100010;
const int M = 8000010;
int head[N], to[N << 1], nextt[N << 1], cnt = 0;
int n, m, a[N], b[N], c[N], t[N], maxn = 0;
int f[N][30], dep[N], tot = 0, root[N], ans[N];
void add(int x, int y) {
	nextt[++cnt] = head[x];
	to[cnt] = y; head[x] = cnt;
}
struct node {
	int l, r, s, num;//s表示数量,num表示数量最多的救济粮的类型
};
void dfs(int x, int fath) {//处理LCA倍增数组
	f[x][0] = fath;
	dep[x] = dep[fath] + 1;
	for(int i = 1; i <= 26; i++) f[x][i] = f[f[x][i - 1]][i - 1];
	for(int i = head[x]; i; i = nextt[i]) {
		if(to[i] != fath) dfs(to[i], x);
	}
}
int lca(int x, int y) {//LCA
	if(dep[x] < dep[y]) swap(x, y);
	for(int i = 26; i >= 0; i--) {
		if(dep[f[x][i]] >= dep[y]) x = f[x][i];
	}
	if(x == y) return x;
	for(int i = 26; i >= 0; i--) {
		if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
	}
	return f[x][0];
}
struct Tree {
	node e[M];
	void update(int i) {
		if(e[e[i].l].s == 0) e[i].s = e[e[i].r].s, e[i].num = e[e[i].r].num;
		else if(e[e[i].r].s == 0) e[i].s = e[e[i].l].s, e[i].num = e[e[i].l].num;
		else if(e[e[i].l].s >= e[e[i].r].s) {
			e[i].s = e[e[i].l].s; e[i].num = e[e[i].l].num;
		} else {
			e[i].s = e[e[i].r].s; e[i].num = e[e[i].r].num;
		}
	}
	int build() {
		tot++;
		e[tot].l = e[tot].r = e[tot].s = e[tot].num = 0;
		return tot;
	}
	void insert(int i, int l, int r, int pos, int k) {
		if(l == r)  {
			e[i].s += k; e[i].num = pos;
			return ;
		}
		int mid = (l + r) >> 1;
		if(pos <= mid) {
			if(e[i].l == 0) e[i].l = build();
			insert(e[i].l, l, mid, pos, k);
		} else {
			if(e[i].r == 0) e[i].r = build();
			insert(e[i].r, mid + 1, r, pos, k);
		}
		update(i);
	}
	int get(int deg) {//查询deg结点中的最大数量的类型
		return e[root[deg]].s == 0 ? 0 : e[root[deg]].num;
	}
	int merge(int p, int q, int l, int r) {
		if(!p) return q;
		if(!q) return p;
		if(l == r) {
			e[p].s += e[q].s; return p;
		}
		int mid = (l + r) >> 1;
		e[p].l = merge(e[p].l, e[q].l, l, mid);
		e[p].r = merge(e[p].r, e[q].r, mid + 1, r);
		update(p);
		return p;
	}
} T;
void dfs1(int x, int fath) {
	for(int i = head[x]; i; i = nextt[i]) {
		if(to[i] == fath) continue;
		dfs1(to[i], x);
		root[x] = T.merge(root[x], root[to[i]], 1, maxn);
	}
	ans[x] = T.get(x);
}

int main() {
//	freopen("data.in", "r", stdin);
	scanf("%d%d", &n, &m);
	for(int i = 1, x, y; i < n; i++) {
		scanf("%d%d", &x, &y);
		add(x, y); add(y, x);
	}
	for(int i = 0; i <= n; i++) root[i] = T.build();//新建根结点,用root记录
	dfs(1, 0);
	for(int i = 1; i <= m; i++) {
		scanf("%d%d%d", &a[i], &b[i], &c[i]);
		maxn = max(maxn, c[i]);
	}
	maxn++;
	for(int i = 1; i <= m; i++) {
		T.insert(root[a[i]], 1, maxn, c[i], 1); T.insert(root[b[i]], 1, maxn, c[i], 1);
		int w = lca(a[i], b[i]);
		T.insert(root[w], 1, maxn, c[i], -1); T.insert(root[f[w][0]], 1, maxn, c[i], -1);
	}
	dfs1(1, 0);
	for(int i = 1; i <= n; i++) printf("%d\n", ans[i]);
	return 0;
}

Guess you like

Origin www.cnblogs.com/mcggvc/p/12567063.html