列表

详情


NC20232. [JSOI2016]轻重路径

描述

JYY 最近学习了一种处理树形结构的高级技巧,叫“轻重路径剖分”。这种技 术会将树中的边划分成轻边和重边。相连的重边会形成一些树上相离的路径。“轻 重路径剖分”可以使得从树上任意一点走到根,都至多只会经过O(logN)条不同 的重路径。
如果你不了解轻重路径剖分,JYY 在这里简单介绍一下:
对于一棵有根树中的任意一个点 u,我们用size(u)表示其为根的子树中的点 的数量。对于 u 的所有孩子中,我们选出size(⋅) 值最大的孩子 v,并将边〈u,v〉设置成重边,u 和其他孩子之间的边我们均设置为轻边。
为了简化问题,这里 JYY 仅考虑一颗 N 个点的有根二叉树。这 N 个点由 1 到 N 编号。并且如果 u 存在两个size(⋅)值一样的孩子,则我们默认 u 和其左孩子的连边为重边。
现在 JYY 希望执行额外 Q 次删点操作,每次 JYY 会随机删掉一个当前二叉 树的叶子节点,而你则需要动态的维护这棵树的轻重路径剖分。
为了方便输出,你只需要在每次操作后输出所有重边指向的点的权值和即可。
如果删除一个点之后,存在一个点 u 拥有两个size(⋅)值一样的孩子,则我们保持 u 在该操作执行之前的重边划分。

输入描述

输入文件的第一行包含一个整数 N。
接下来 N 行,第 i 行包含两个整数Li,Ri,表示编号为 i 的点的左孩子编号和右孩子编号;Li= 0表示点 i 没有左孩子,Ri = 0表示点 i 没有右孩子。 
第 N+2 行包含一个整数 Q,表示 JYY 进行的删点操作。 
第 N+3 行包含 Q 个空格分开的正整数,表示 JYY 删去的叶子的编号。
输入数据保证每次删除操作均删除了一个叶子。

输出描述

输出 Q+1 行,每行包含一个整数,表示在轻重路径剖分中所有重边指向的
点的编号的和。其中第一行对应初始的路径剖分,之后的 Q 行对应进行了相应删点操作之后路径划分。

示例1

输入:

8
2 3
4 5
0 0
6 7
0 8
0 0
0 0
0 0
7
6 7 8 5 4 2 3

输出:

20
21
15
7
6
2
3
0

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++11(clang++ 3.9) 解法, 执行用时: 632ms, 内存消耗: 18788K, 提交时间: 2019-03-09 15:43:08

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 200005;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
struct BinaryIndextree {
	int a[MAXN], n;
	int Log, bit[MAXN];
	void init(int x) {
		n = x; bit[Log = 0] = 1;
		while (bit[Log] * 2 <= n) {
			Log++;
			bit[Log] = bit[Log - 1] << 1;
		}
		memset(a, 0, sizeof(a));
	}
	void modify(int pos, int d) {
		for (int i = pos; i <= n; i += i & -i)
			a[i] += d;
	}
	int query(int l, int r) {
		int ans = 0;
		for (int i = r; i >= 1; i -= i & -i)
			ans += a[i];
		for (int i = l - 1; i >= 1; i -= i & -i)
			ans -= a[i];
		return ans;
	}
	int pred(int pos, int val) {
		if (val == 0) return 0;
		int ans = 0;
		for (int i = Log; i >= 0; i--)
			if (ans + bit[i] <= n && a[ans + bit[i]] < val) {
				ans += bit[i];
				val -= a[ans];
			}
		return ans + 1;
	}
} Size, Light;
struct SegmentTree {
	struct Node {
		int lc, rc;
		int Max;
	} a[MAXN * 2];
	int root, size, n;
	void build(int &root, int l, int r) {
		root = ++size;
		if (l == r) return;
		int mid = (l + r) / 2;
		build(a[root].lc, l, mid);
		build(a[root].rc, mid + 1, r);
	}
	void update(int root) {
		a[root].Max = max(a[a[root].lc].Max, a[a[root].rc].Max);
	}
	void init(int x) {
		n = x;
		size = root = 0;
		build(root, 1, n);
	}
	void modify(int root, int l, int r, int pos, int val) {
		if (l == r) {
			a[root].Max = val;
			return;
		}
		int mid = (l + r) / 2;
		if (mid >= pos) modify(a[root].lc, l, mid, pos, val);
		else modify(a[root].rc, mid + 1, r, pos, val);
		update(root);
	}
	void modify(int pos, int val) {
		modify(root, 1, n, pos, val);
	}
	int query(int root, int l, int r, int ql, int qr) {
		if (l == ql && r == qr) return a[root].Max;
		int mid = (l + r) / 2, ans = 0;
		if (mid >= ql) chkmax(ans, query(a[root].lc, l, mid, ql, min(mid, qr)));
		if (mid + 1 <= qr) chkmax(ans, query(a[root].rc, mid + 1, r, max(mid + 1, ql), qr));
		return ans;
	}
	int query(int l, int r) {
		return query(root, 1, n, l, r);
	}
} ST;
struct Node {
	int lc, rc;
	int father;
	int dfn, rit;
	int up, size;
} a[MAXN];
int n, q, timer, pos[MAXN], home[MAXN];
long long ans[MAXN], curr;
bool vis[MAXN], intree[MAXN];
void renew(int pos) {
	int size = Size.query(a[pos].dfn, a[pos].rit);
	int f = a[pos].father;
	if (a[f].lc == pos) {
		int tmp = a[f].rc, tsize = Size.query(a[tmp].dfn, a[tmp].rit);
		if (!intree[tmp] || size > tsize) {
			Light.modify(a[pos].dfn, -1);
			if (intree[tmp]) Light.modify(a[tmp].dfn, 1);
			curr += pos;
			if (intree[tmp]) curr -= tmp;
		} else if (size == tsize) {
			int nxtp = ST.query(a[pos].dfn, a[pos].rit);
			int nxtt = ST.query(a[tmp].dfn, a[tmp].rit);
			if (nxtp >= nxtt) {
				Light.modify(a[pos].dfn, -1);
				Light.modify(a[tmp].dfn, 1);
				curr += pos;
				curr -= tmp;
			}
		}
	} else {
		int tmp = a[f].lc, tsize = Size.query(a[tmp].dfn, a[tmp].rit);
		if (!intree[tmp] || size > tsize) {
			Light.modify(a[pos].dfn, -1);
			if (intree[tmp]) Light.modify(a[tmp].dfn, 1);
			curr += pos;
			if (intree[tmp]) curr -= tmp;
		} else if (size == tsize) {
			int nxtp = ST.query(a[pos].dfn, a[pos].rit);
			int nxtt = ST.query(a[tmp].dfn, a[tmp].rit);
			if (nxtp > nxtt) {
				Light.modify(a[pos].dfn, -1);
				Light.modify(a[tmp].dfn, 1);
				curr += pos;
				curr -= tmp;
			}
		}
	}
} 
void work(int pos, int up) {
	a[pos].up = up;
	a[pos].dfn = ++timer;
	if (a[pos].lc == 0 && a[pos].rc != 0) work(a[pos].rc, up);
	if (a[pos].rc == 0 && a[pos].lc != 0) work(a[pos].lc, up);
	if (a[pos].lc != 0 && a[pos].rc != 0) {
		if (a[a[pos].lc].size >= a[a[pos].rc].size) {
			work(a[pos].lc, up);
			work(a[pos].rc, a[pos].rc);
		} else {
			work(a[pos].rc, up);
			work(a[pos].lc, a[pos].lc);
		}
	}
	a[pos].rit = timer;
}
void dfs(int pos) {
	a[pos].size = 1;
	if (a[pos].lc) {
		dfs(a[pos].lc);
		a[pos].size += a[a[pos].lc].size;
	}
	if (a[pos].rc) {
		dfs(a[pos].rc);
		a[pos].size += a[a[pos].rc].size;
	}
}
int main() {
	read(n);
	for (int i = 1; i <= n; i++) {
		read(a[i].lc), read(a[i].rc);
		if (a[i].lc != 0) a[a[i].lc].father = i;
		if (a[i].rc != 0) a[a[i].rc].father = i;
	}
	dfs(1);
	work(1, 1);
	ST.init(n);
	Size.init(n);
	Light.init(n);
	for (int i = 1; i <= n; i++)
		home[a[i].dfn] = i;
	read(q);
	for (int i = 1; i <= q; i++) {
		read(pos[i]);
		vis[pos[i]] = true;
	}
	int point = q;
	for (int i = n; i >= 2; i--)
		if (!vis[home[i]]) pos[++point] = home[i];
	Size.modify(a[1].dfn, 1);
	intree[1] = true;
	for (int i = 1; i <= point; i++)
		ST.modify(a[pos[i]].dfn, i);
	for (int i = point; i >= 1; i--) {
		int now = pos[i];
		intree[now] = true;
		ST.modify(a[now].dfn, 0);
		Size.modify(a[now].dfn, 1);
		Light.modify(a[now].dfn, 1);
		renew(now); now = a[now].father;
		while (now != 0) {
			int tmp = Light.pred(a[now].dfn, Light.query(1, a[now].dfn));
			if (tmp >= a[a[now].up].dfn) {
				now = home[tmp];
				renew(now);
				now = a[now].father;
			} else now = a[a[now].up].father;
		}
		ans[i] = curr;
	}
	for (int i = 1; i <= q + 1; i++)
		printf("%lld\n", ans[i]);
	return 0;
}

上一题