Codeforces Round #417 (Div. 2) D. Sagheer and Kindergarten(树中判祖先)

http://codeforces.com/contest/812/problem/D

题意:

现在有n个孩子,m个玩具,每次输入x y,表示x孩子想要y玩具,如果y玩具没人玩,那么x就可以去玩,如果y有人玩的话,x就必须等待y玩完后才能玩。如果出现循环,那么这个循环里的孩子都会哭。

现在有q次询问,如果加入x y,会有多少孩子哭。

 

思路:

建立一棵树,根结点就是第一个玩玩具y的人,它的子树就是等待玩具的人(子树按照等待顺序建树)。这样就会形成很多棵树。

这样的话,对于每个询问,我们去找到最后一个玩y玩具的人,只有y玩完了那才会给x,那么这样的话这两个人也应该连一条边,如果连边后形成了环,那么这个环里的顶点数就是哭的孩子数。

其实这就是判断祖先的问题,如果x是最后一个玩y玩具的人的祖先,那么他们连边后肯定是要形成环的。

 

那么怎么判断两个点的祖先关系呢?

对树dfs,记录每个顶点的访问次序标号in和结束访问标号out,如果x是y的祖先就需要满足in【i】<in【y】<out【i】

在这道题目中每个人最多只会等待一个玩具,所以在树中,每个结点最多只有一个子节点,那么我们就可以根据out和in标记来计算环中的顶点个数。

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<sstream>
 6 #include<vector>
 7 #include<stack>
 8 #include<queue>
 9 #include<cmath>
10 #include<map>
11 using namespace std;
12 typedef long long ll;
13 typedef pair<int,long long> pll;
14 const int INF = 0x3f3f3f3f;
15 const int maxn=1e5+5;
16 
17 int n,m,k,q;
18 vector<int> g[maxn];
19 int in[maxn],out[maxn];
20 int vis[maxn];
21 int dfs_clock;
22 
23 //记录访问标记和结束标记
24 void dfs(int u)
25 {
26     in[u]=++dfs_clock;
27     for(int i=0;i<g[u].size();i++)
28     {
29         dfs(g[u][i]);
30     }
31     out[u]=dfs_clock;
32 }
33 
34 int main()
35 {
36     //freopen("input.txt","r",stdin);
37     scanf("%d%d%d%d",&n,&m,&k,&q);
38     for(int i=1;i<=k;i++)
39     {
40         int x,y;
41         scanf("%d%d",&x,&y);
42         if(vis[y])
43         {
44             g[vis[y]].push_back(x);  //x需要等待,vis[y]玩好后给x
45         }
46         vis[y]=x;
47     }
48     dfs_clock=0;
49     for(int i=1;i<=n;i++)
50     {
51         if(!in[i])
52             dfs(i);
53     }
54 
55     while(q--)
56     {
57         int x,y;
58         scanf("%d%d",&x,&y);
59         y=vis[y];  //找到最后一个玩y的人
60         if(in[x]<=in[y] && out[x]>=in[y])
61             printf("%d\n",out[x]-in[x]+1);
62         else
63             puts("0");
64     }
65 
66     return 0;
67 }

 

posted @ 2017-06-11 10:24  Kayden_Cheung  阅读(323)  评论(0编辑  收藏  举报
//目录