1. 程式人生 > >計蒜客NOIP模擬賽4 D2T2 跑步愛天天

計蒜客NOIP模擬賽4 D2T2 跑步愛天天

數組 urn memset 我們 ng- int str 100% 序列

YOUSIKI 在 noip2016 的一道《天天愛跑步》的題爆零後,潛心研究樹上問題,成為了一代大師,於是皮皮妖為了測驗他,出了一道題,名曰《跑步愛天天》。

有一個以 1 為根的有根樹,初始每個點都有個警衛,每個警衛會按深度優先的順序周期性的巡邏以其初始點為根的子樹(詳見樣例解釋),一個時刻走且僅走一條邊。

YOUSIKI 初始在 x 點,他要到根結點拜訪皮皮妖,他會沿著最短路徑走,一個時刻走且僅走一條邊,當他走到這個點時,如果遇到了警衛,他會消耗 1點妖氣將這個警衛殺死,殺死後的警衛就不會在以後的路程中出現。

那麽 YOUSIKI 需要消耗幾點妖氣才能拜訪到皮皮妖呢?

輸入格式

第一行一個數字 T,表示有 T 組數據。

對於每組數據,第一行一個整數 n,表示樹有 n個結點。

接下來 n 行,第 i 行有一個整數 k,表示 i號點兒子個數,接下來 k 個整數,表示 k 個有序兒子 (“有序” 的含義詳見樣例解釋)。

最後一行一個整數 x,表示 YOUSIKI 的出發點。

輸出格式

輸出 T 行,每行一個整數表示答案。

數據範圍

對於 20% 的數據,n≤100

對於 40% 的數據:n≤2000

對於另外 10% 的數據:樹高 ≤5

對於另外 10% 的數據:樹是一條鏈。

對於 100% 的數據:T10,n≤500000

樣例解釋

為了方便,我們把初始在 iii 號點的警衛稱為警衛 iii。

警衛 1 的一個周期內的巡邏路線為:1->2->4->2->5->2->1->3->6->3->1。

警衛 2 的一個周期內的巡邏路線為:2->4->2->5->2。

警衛 3 的一個周期內的巡邏路線為:3->6->3。

警衛 4,5,6 一直不動。

YOUSIKI 的路線為:6->3->1。

YOUSIKI 初始在 6 號點,需要殺掉警衛 6。第一時刻他在 3 號點,雖然他和警衛 3 對穿過去,但是由於沒有在點上相遇,所以不算相遇。第二時刻他在 1 號點,此時 111 號點沒有警衛。

註意

  1. 警衛的巡邏是周期性的,例如,初始在 2 號點警衛的巡邏路線為:2->4->2->5->2->4->2->5->2->4->2->5->2->...

  2. 輸入格式中的 “有序” 指的是比如 1 號點的兒子先輸入的 2 再輸入的 3,那麽 1 號點巡邏時就要先巡邏 2 再巡邏 3

樣例輸入

1
6
2 2 3
2 4 5
1 6
0
0
0
6

樣例輸出

1

我們先把整個樹 dfs 一遍,遇到一個點就把這個點記錄到一個數組後邊,
即求出了樹的歐拉序,顯然如果不考慮循環的話,guard是在這個序列上每次往後走一個,起始位置就是第i個點第一次出現的位置

假設 YOUSIKI 現在走到了 x 點,過了 t 秒,那麽我們在這個序列上遍歷 x 出現的所有位置,
並查看這個位置往前 t 個是否為 x 的祖先,如果是,把那個祖先標為1,表示已被消滅


坑點1:因為要按輸入順序遍歷子節點,而鏈式前向星建出的圖是從後往前的

所以要把加邊的順序反過來

坑點2:相遇的警衛只能是往下走的,且起始位置為第一個出現的i,所以第前t個

祖先必須是第一個出現的

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 struct Node
 7 {
 8     int next,to;
 9 }edge[5000001];
10 int num,head[5000001],dep[5000001],dfn[20000001];
11 int s,cl,tot,t[5000001],n,ans,f[5000001],st[5000001];
12 bool vis[5000001],mark[5000001];
13 int gi()
14 {
15     char ch=getchar();
16     int x=0;
17     while (ch<0||ch>9) ch=getchar();
18     while (ch>=0&&ch<=9) 
19     {
20         x=x*10+ch-0;
21         ch=getchar();
22     }
23     return x;
24 }
25 void add(int u,int v)
26 {
27     num++;
28     edge[num].next=head[u];
29     head[u]=num;
30     edge[num].to=v;
31 }
32 void dfs(int x)
33 {int i;
34     dfn[++tot]=x;f[tot]=1;
35     mark[x]=(x==s);
36     for (i=head[x];i;i=edge[i].next)
37     {
38         int v=edge[i].to;
39         dep[v]=dep[x]+1;
40         dfs(v);
41         if (mark[v]) mark[x]=1;
42         dfn[++tot]=x;f[tot]=0;
43     }
44     if (mark[x]) t[x]=cl++;
45 }
46 int main()
47 {int T,i,j,k,x;
48   cin>>T;
49     while (T--)
50     {
51         memset(head,0,sizeof(head));
52         num=0;cl=0;tot=0;
53         memset(mark,0,sizeof(mark));
54         memset(dep,0,sizeof(dep));
55         memset(t,0,sizeof(t));
56         memset(f,0,sizeof(f));
57         n=gi();
58         for (i=1;i<=n;i++)
59         {
60            k=gi();
61             for (j=1;j<=k;j++)
62             {
63                 st[j]=gi();
64             }
65             for (j=k;j>=1;j--)
66                 add(i,st[j]);
67         }
68         s=gi();
69         dep[1]=1;
70         dfs(1);
71         ans=0;
72         memset(vis,0,sizeof(vis));
73         int u,v;
74         for (i=1;i<=tot;i++)
75         {
76             if (mark[u=dfn[i]]&&i>t[u]&&f[i-t[u]])
77             if (mark[v=dfn[i-t[u]]]&&dep[v]<=dep[u])
78                 if (vis[v]==0)
79                      {
80                          ans++;
81                          vis[v]=1;
82                      }
83         }
84         cout<<ans<<endl;
85     }
86 }

計蒜客NOIP模擬賽4 D2T2 跑步愛天天