CF GYM 2018 USP-ICMC I题

CF GYM 2018 USP-ICMC I题

题目链接:
http://codeforces.com/gym/101875/problem/I
题目描述:
CF GYM 2018 USP-ICMC I题_第1张图片
输入输出:
CF GYM 2018 USP-ICMC I题_第2张图片
样例:
CF GYM 2018 USP-ICMC I题_第3张图片
题目大意:
有n个人,m个询问,这n个人的编号为0~n-1,他们要去一个聚会,已知这n个人的每个人的唯一朋友是谁(若无朋友表示为-1),只有当这个唯一朋友去聚会时这个人才会去聚会。询问两个数x和y,问若x去了聚会,y是否一定回去这个聚会?
数据范围:
2 ≤ N ≤ 1 × 105
1 ≤ Q ≤ 2 × 105
ai =  - 1 or 0 ≤ ai ≤ N - 1
0 ≤ xj, yj ≤ N - 1
解题思路:
因一个人若有朋友就只有一个唯一朋友,所以可能会有多个人把一个人当朋友,那我可以选择反向建图,将没有朋友(即ai=-1)的这个人当做根节点建一个一对多的树,可以用vector存。这道题询问x去聚会y是否一定去聚会,就是问x是不是y的孩子节点。从根节点跑DFS序,即跑一遍DFS,用l数组记录每个数最先出现的位置,r数组记录每个数最后出现的位置,对于每一个询问只需O(1)的复杂度,即判断一下x是不是y的孩子,若l[y]<=l[x] && r[x]<=r[y],即若x最先出现的位置与最后出现的位置,正好夹在y最先出现的位置与最后出现的位置的中间,则x是y的孩子。所以这个题主要要会DFS序。
代码:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<map>
#include<vector>
using namespace std;
vector<int> G[100005];
int ind[100005], l[100005], r[100005];
int cnt;
void DFS(int x){
	l[x] = ++cnt;
	int len = G[x].size();
	for(int i = 0;i < len;i++) DFS(G[x][i]);
	r[x] = cnt;
}
int main(){
	int n, m;
	scanf("%d %d", &n, &m);
	//memset(G, 0, sizeof(G));
	for(int i = 0;i < n;i++){
		int v;
		scanf("%d", &v);
		if(v != -1){
			G[v].push_back(i);
			ind[i]++;
		}
	}
	for(int i = 0;i < n;i++){
		if(ind[i] == 0) DFS(i);
	}
	while(m--){
		int x, y;
		scanf("%d %d", &x, &y);
		if(l[y] <= l[x] && r[x] <= r[y]) printf("Yes\n");
		else printf("No\n");
	}
	return 0;
}

你可能感兴趣的:(CF GYM 2018 USP-ICMC I题)