傳送門ios
•參考資料
[1]:CodeForces 825G Educational Round #25 G :建樹選根大法+O1大法+iostream解綁了仍是慢c++
•題意
給定一顆包含 n 個節點的樹,開始樹的全部節點都是白色的;ide
給出 q 次詢問,詢問分爲一、2兩種:ui
- 將節點 x 塗成黑色。
- 詢問節點 x 到全部的黑點節點的簡單路徑中的標號最小的那個點(包括起點和黑點)
題目保證第一次詢問是 1 類型的。url
•題解
若是咱們隨便選取某節點做爲根節點,那麼詢問的時候,咱們要找到節點 x 到全部黑色節點的 LCA;spa
可是這樣顯然會超時的,因此咱們換一種建樹方法。3d
因爲第一個詢問必然是 1 類型,那麼咱們就把第一次詢問的那個變黑的點做爲根節點,看一下這樣有什麼好處;code
定義 $res_i$ 表示節點 i 到根節點(詢問1的x)的路徑中,標號最小的節點;blog
首先,咱們預處理出全部的 $res$,只需 $DFS$ 一遍便可,時間複雜度 $O(n)$;get
接下來,若是剩餘的詢問所有是 2 類型,那麼,對於節點 x 的詢問,直接輸出 $res_x$ 便可;
可是,若是存在 1 類型的詢問呢?
對於新的黑色節點 $u_1,u_2,.....$,在查詢節點 x 的時候,除了須要知道節點 x 到根節點路徑上標號最小的節點;
同時還須要求出節點 x 到黑色節點 $u_i$ 路徑上標號最小的節點;
你會發現,求解節點 x 到黑色節點 $u_i$ 路徑上的標號最小的節點等價於求解根節點到黑色節點 $u_i$ 路徑上的標號最小的節點;
那這麼說的話,咱們就能夠定義一個變量 $Min$,用來存儲新加入的黑色節點到根節點的路徑上標號最小的節點信息;
詢問的時候,只需輸出 $res_x$ 和 $Min$ 的最小值便可;
•Code
View Code1 #include<bits/stdc++.h> 2 using namespace std; 3 #define INF 0x3f3f3f3f 4 #define mem(a,b) memset(a,b,sizeof(a)) 5 const int maxn=1e6+50; 6 7 int n,q; 8 int num; 9 int head[maxn]; 10 struct Edge 11 { 12 int to; 13 int next; 14 }G[maxn<<1]; 15 void addEdge(int u,int v) 16 { 17 G[num]={v,head[u]}; 18 head[u]=num++; 19 } 20 int res[maxn]; 21 22 void DFS(int u,int f) 23 { 24 res[u]=min(u,res[f]); 25 for(int i=head[u];~i;i=G[i].next) 26 { 27 int v=G[i].to; 28 if(v != f) 29 DFS(v,u); 30 } 31 } 32 void Solve() 33 { 34 mem(res,INF); 35 36 int ans=0; 37 int Min=INF; 38 for(int i=1;i <= q;++i) 39 { 40 int t,z; 41 scanf("%d%d",&t,&z); 42 int x=(z+ans)%n+1; 43 44 if(i == 1) 45 DFS(x,x); 46 else if(t == 1) 47 Min=min(Min,res[x]); 48 else 49 { 50 ans=min(Min,res[x]); 51 printf("%d\n",ans); 52 } 53 } 54 } 55 void Init() 56 { 57 num=0; 58 mem(head,-1); 59 } 60 int main() 61 { 62 Init(); 63 scanf("%d%d",&n,&q); 64 for(int i=1;i < n;++i) 65 { 66 int u,v; 67 scanf("%d%d",&u,&v); 68 addEdge(u,v); 69 addEdge(v,u); 70 } 71 Solve(); 72 73 return 0; 74 }