ming 茗

Description

给你两棵有 (N) 个点的树,保证每个点的父亲的编号比自己小。每次询问给出 (p_1, p_2) ,设 (S_1) 为第一棵树中 (p_1) 到根的路径上的点的编号的集合, (S_2) 为第二棵数中 (p_2) 到根的路径上的点的编号的集合,设 (p_3)(S_1cap S_2) 中的最大元素,求 (p_3) 以及在第一棵树中 (p_1,p_3) 的距离和第二棵树中 (p_2,p_3) 的距离。

Input

第一行两个正整数 (N,M) 代表点的个数和询问组数。

第二行 (N-1) 个数,代表第一棵树中 (2) 号点到 (N) 号点的父亲。

第三行 (N-1) 个数,代表第二棵树中 (2) 号点到 (N) 号点的父亲。

接下来 (M) 行,每行两个数 (p_1,p_2) 代表一组询问。这里的 (p_1,p_2) 均需要解密,如果设上次询问的答案为 (p_3) (如果是第一次询问,则 (p_3=0) ),那么我们需要计算 (p_1=(p_1 + p_3) mod N + 1,p_2=(p_2+p_3) mod N+1) 来得到实际的 (p_1,p_2)

Output

(M) 行,每行三个数代表答案。

Sample

Sample Input 1

5 1
1 2 3 3
1 1 3 2
4 3

Sample Output 1

3 2 2

Sample Input 2

5 3
1 1 2 2
1 2 2 1
5 3
5 4
3 5

Sample Output 2

1 1 3
1 2 1
2 2 1

Sample Input 3

5 3
1 1 2 2
1 2 3 1
1 4
1 1
3 4

Sample Output 4

1 2 2
3 1 1
2 1 2

Limit

对于 (50\%) 的数据, (1le N,Mle 10^3)

对于 (100\%) 的数据, (1le N,Mle 10^5)

Solution

这题的主席树做法太妙了!

以第一棵树的父子关系建线段树,以第二棵树的 (mathrm{dfs}) 序作为区间。

什么意思呢?

比如,第二棵树里的点 (3)(mathrm{dfs}) 区间为 ([2,6]) ,我们就在第一棵树中以 (3) 的父亲作为基础建主席树,把 ([2,6]) 全部赋值为 (3) 就可以了。

啊……好难讲啊(我太菜了),还是看代码好理解。

#include<bits/stdc++.h> 
using namespace std;
#define N 100001
#define rep(i, a, b) for (int i = a; i <= b; i++)
inline int read() {
	int x = 0, flag = 1; char ch = getchar(); while (!isdigit(ch)) { if (!(ch ^ '-')) flag = -1; ch = getchar(); }
	while (isdigit(ch)) x = (x << 1) + (x << 3) + ch - '0', ch = getchar(); return x * flag;
}
int n, m, head[N], tot = 1, fa[2][N], dep[2][N], l[N], r[N], ind;
struct edge { int v, next; }e[N];
inline void add(int u, int v) { e[++tot].v = v, e[tot].next = head[u], head[u] = tot; }
void dfs(int t, int u) {
	if (t) l[u] = ++ind;
	for (int i = head[u]; i; i = e[i].next) dep[t][e[i].v] = dep[t][u] + 1, dfs(t, e[i].v);
	if (t) r[u] = ind;
}
struct node { int val, ls, rs; }T[N * 40];
int root[N], ndCnt;
#define mid (l + r >> 1)
int modify(int pre, int l, int r, int L, int R, int val) {
	int now = ++ndCnt; T[now] = T[pre];
	if (l >= L && r <= R) { T[now].val = val; return now; }
	if (L <= mid) T[now].ls = modify(T[pre].ls, l, mid, L, R, val);
	if (R > mid) T[now].rs = modify(T[pre].rs, mid + 1, r, L, R, val);
	return now;
}
int query(int rt, int l, int r, int pos) {
	if (!rt) return 0;
	int ret = T[rt].val;
	if (pos <= mid) ret = max(ret, query(T[rt].ls, l, mid, pos));
	else ret = max(ret, query(T[rt].rs, mid + 1, r, pos));
	return ret;
}
int main() {
	n = read(), m = read();
	rep(i, 2, n) fa[0][i] = read();
	rep(i, 2, n) { fa[1][i] = read(); add(fa[1][i], i); }
	dep[1][1] = 1, dfs(1, 1);
	memset(head, 0, sizeof head); tot = 1; rep(i, 2, n) add(fa[0][i], i);
	dep[0][1] = 1, dfs(0, 1);
	rep(i, 1, n) root[i] = modify(root[fa[0][i]], 1, n, l[i], r[i], i);
	int ans = 0;
	while (m--) {
		int p1 = (read() + ans) % n + 1, p2 = (read() + ans) % n + 1;
		ans = query(root[p1], 1, n, l[p2]);
		printf("%d %d %d
", ans, dep[0][p1] - dep[0][ans] + 1, dep[1][p2] - dep[1][ans] + 1);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/aziint/p/8479448.html