CodeForces 825G"Tree Queries"(选根建树)

 

传送门

 

•参考资料

  [1]:CodeForces 825G Educational Round #25 G :建树选根大法+O1大法+iostream解绑了还是慢

•题意

  给定一颗包含 n 个节点的树,开始树的所有节点都是白色的;

  给出 q 次询问,询问分为1、2两种:

    1. 将节点 x 涂成黑色。
    2. 询问节点 x 到所有的黑点节点的简单路径中的标号最小的那个点(包括起点和黑点)

  题目保证第一次询问是 1 类型的。

•题解

  如果我们随便选取某节点作为根节点,那么询问的时候,我们要找到节点 x 到所有黑色节点的 LCA;

  但是这样显然会超时的,所以我们换一种建树方法。

  由于第一个询问必然是 1 类型,那么我们就把第一次询问的那个变黑的点作为根节点,看一下这样有什么好处;

  定义 $res_i$ 表示节点 i 到根节点(询问1的x)的路径中,标号最小的节点;

  首先,我们预处理出所有的 $res$,只需 $DFS$ 一遍即可,时间复杂度 $O(n)$;

  接下来,如果剩余的询问全部是 2 类型,那么,对于节点 x 的询问,直接输出 $res_x$ 即可;

  但是,如果存在 1 类型的询问呢?

  对于新的黑色节点 $u_1,u_2,.....$,在查询节点 x 的时候,除了需要知道节点 x 到根节点路径上标号最小的节点;

  同时还需要求出节点 x 到黑色节点 $u_i$ 路径上标号最小的节点;

  你会发现,求解节点 x 到黑色节点 $u_i$ 路径上的标号最小的节点等价于求解根节点到黑色节点 $u_i$ 路径上的标号最小的节点;

  那这么说的话,我们就可以定义一个变量 $Min$,用来存储新加入的黑色节点到根节点的路径上标号最小的节点信息;

  询问的时候,只需输出 $res_x$ 和 $Min$ 的最小值即可; 

•Code

 1 #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 }
View Code

 

posted @ 2019-10-24 18:03  HHHyacinth  阅读(60)  评论(0编辑  收藏