計蒜客NOIP模擬賽4 D2T2 跑步愛天天
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% 的數據:T≤10,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 號點沒有警衛。
註意
-
警衛的巡邏是周期性的,例如,初始在 2 號點警衛的巡邏路線為:2->4->2->5->2->4->2->5->2->4->2->5->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 跑步愛天天