1 条题解

  • 3
    @ 2021-11-9 20:52:36

    CF208E 题解

    给定一片 nn 个点的森林,森林中的树都有根。 mm 次询问,每次询问一个点 xx 与多少个点有相同的 KK 级祖先。 1n1051 \le n \le 10^51m1051 \le m \le 10^5

    离线做法,首先用倍增对于每个询问求出 xxKK 级祖先,用 vector\tt{vector} 或链表把询问挂在祖先上,问题转换成求一个点有多少个 KK 级儿子的问题。

    对每个节点,以深度为下标建立权值线段树,进行 dfs\tt{dfs}。若 dfs\tt{dfs} 到一个节点 xx,在线段树插入当前点的深度并与子节点的线段树合并。然后遍历所有询问,对于询问这个点有多少个 KK 级儿子,在线段树中查询深度为 depx+Kdep_x + K 的节点有多少个即可。别忘了答案要减一。

    时间复杂度 Θ(nlogn)\Theta(n \log n)


    CODE
    #include <bits/stdc++.h>
    using namespace std;
    
    inline int read() {
    	int x = 0, f = 0; char c = 0;
    	while (!isdigit(c)) f |= c == '-', c = getchar();
    	while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    	return f ? -x : x;
    }
    
    #define N 100010
    #define pb push_back
    #define PII pair<int, int>
    #define mp make_pair
    #define fi first
    #define se second
    
    int n, m, res[N], f[N][22], rt[N], dep[N];
    vector<int> e[N], root;
    vector<PII> q[N];
    
    struct Segment_tree {
    	int l, r, ls, rs, sum;
    	#define lid tr[id].ls
    	#define rid tr[id].rs
    }tr[N * 20];
    int cnt = 0;
    void Add(int &id, int l, int r, int x) {
    	if (!id) id = ++ cnt;
    	tr[id].l = l, tr[id].r = r;
    	if (l == r) {
    		tr[id].sum ++;
    		return;
    	}
    	int mid = tr[id].l + tr[id].r >> 1;
    	if (x <= mid) Add(lid, l, mid, x);
    	if (x > mid) Add(rid, mid + 1, r, x);
    }
    int Ask(int id, int l, int r, int x) {
    	if (!id) return 0;
    	if (l == r) return tr[id].sum;
    	int mid = tr[id].l + tr[id].r >> 1;
    	if (x <= mid) return Ask(lid, l, mid, x);
    	if (x > mid) return Ask(rid, mid + 1, r, x);
    }
    void Merge(int &x, int y, int l, int r) {
    	if (!x || !y) return x += y, void();
    	if (l == r) {
    		tr[x].sum += tr[y].sum;
    		return;
    	}
    	int mid = tr[x].l + tr[x].r >> 1;
    	Merge(tr[x].ls, tr[y].ls, l, mid);
    	Merge(tr[x].rs, tr[y].rs, mid + 1, r);
    }
    
    void dfs2(int x, int fa) {
    	Add(rt[x] = ++ cnt, 1, n, dep[x]);
    	for (auto y : e[x]) if (y != fa) {
    		dfs2(y, x), Merge(rt[x], rt[y], 1, n);
    	}
    	for (auto i : q[x]) {
    		res[i.fi] = Ask(rt[x], 1, n, dep[x] + i.se) - 1;
    	}
    }
    
    void dfs1(int x, int fa) {
    	dep[x] = dep[fa] + 1;
    	f[x][0] = fa;
    	for (int i = 1; i <= 20; i ++) {
    		f[x][i] = f[f[x][i - 1]][i - 1];
    	}
    	for (auto y : e[x]) {
    		if (y != fa) dfs1(y, x);
    	}
    }
    
    int main() {
    	n = read();
    	for (int i = 1; i <= n; i ++) {
    		int x = read();
    		if (x) e[x].pb(i), e[i].pb(x);
    		else root.pb(i);
    	}
    
    	for (auto x : root) dfs1(x, 0);
    
    	m = read();
    	for (int i = 1; i <= m; i ++) {
    		int x = read(), y = read(), fa = x;
    		for (int i = 0, j = y; i <= 20; i ++, j >>= 1) {
    			if (j & 1) fa = f[fa][i];
    		}
    		q[fa].pb(mp(i, y));
    	}
    
    	for (auto x : root) dfs2(x, 0);
    
    	for (int i = 1; i <= m; i ++) {
    		printf("%d ", res[i]);
    	} puts("");
    	return 0;
    }
    

    • @ 2021-11-9 21:00:35

      TQL%%%Orz

    • @ 2021-11-9 21:02:02

      @ 您最强了 stOrz

  • 1

信息

ID
6114
时间
2000ms
内存
256MiB
难度
7
标签
递交数
2
已通过
2
上传者