• 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;
    }
    
  • 相关阅读:
    Visual Studio for Mac 2017 初体验
    利用栈求表达式的值
    Problem C: ChongQueue
    Problem G: ZL's Prob.2
    Problem F: ZL's Prob.1
    Problem B: ChongBit
    HDU 5156
    SHUOJ 1771
    OpenGL学习整理------着色器
    OpenGL ES着色器语言----------------储存修饰符
  • 原文地址:https://www.cnblogs.com/aziint/p/8479448.html
Copyright © 2020-2023  润新知