BZOJ3307雨テール(動的セグメントツリー合成オープン点+ツリー+微分)

Nが容易爆発的に、十分な大きさである場合、それはよく知られているセグメントツリー空間複雑度は、O(N * 4)です。
全体の範囲は、再帰的にアクセスするサブツリーを必要とするとき、文字通り唯一のノードの最初の設立に、ツリー構造全体にすべてのアウトを構築する必要はありませんダイナミックオープンポイントは、このサブツリーノードの再確立を表します。完全なバイナリツリーは、ルールの倍の数ではなくなりました。
動的処方セグメントツリーの利点:1は、2つのセグメントツリーと同じ範囲を維持するために組み込まれてもよいです。省スペース2. 省資源社会構築推進
コードの実装を:

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);
}

複合セグメントツリー:
2があり、一方はさらに、ノードが削除される新しいノードにマージされます。
一例として、後者:
2のルートから、2つの変数同期再帰的に2つのツリーをトラバースして、ノードの現在の数をマークします。
1. 1が空の場合は、別のものを返します。
値は、2つのノードのリーフノードに到達すると2を添加します。

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雨テール:
この質問のために、私たちはそれぞれのツリーノードのためのセグメントツリーを構築し、ツリーラインは、その最大値を維持するために救援食料の標準タイプを表します。
方法ツリー差が読み込まれる\(X、Y、Z \ ) の後に、それぞれ、で\(X、Y \)ノードで\(Z \)位置+1に対応する、\(LCA(X、 Y)\)の位置にノード相当- 1 \(父(LCA(X、 Y))\) ノードの対応する位置に-1、従ってレリーフ粒ノードの種類の数は、その子ノードの全てに等しくなることを保証食品と安堵のこのタイプの数。
修正後、再度、DFS、サブツリーツリーラインのマージ、クエリ最大。
コード:

#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;
}

おすすめ

転載: www.cnblogs.com/mcggvc/p/12567063.html