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 }

原文地址:https://www.cnblogs.com/violet-acmer/p/11733860.html

时间: 2024-10-18 17:45:58

CodeForces 825G"Tree Queries"(建树选根)的相关文章

AC日记——825G - Tree Queries

825G - Tree Queries 思路: 神题,路径拆成半链: 代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 1000005 #define INF 0x3f3f3f3f int n,m,val[maxn],head[maxn],E[maxn<<1],V[m

Educational Codeforces Round 25 G. Tree Queries

题目链接:Educational Codeforces Round 25 G. Tree Queries 题意: 给你一棵树,一开始所有的点全是黑色,有两种操作. 1 x 将x这个点变为黑色,保证第一个操作是这个. 2 x 询问x到任意黑色的点的简单路径上的最小节点编号. 题解: 首先将一个变为黑色的点当成树根,然后dfs一下,预处理出所有点的答案. 然后开一个变量记录一下当前变黑的点的答案cur=min(cur,dp[x]). 每次询问的时候答案就是min(cur,dp[x]). 如果觉得很神

Codeforces Round #629 (Div. 3) E. Tree Queries(lca题)

https://codeforces.com/contest/1328/problem/E E. Tree Queries You are given a rooted tree consisting of nn vertices numbered from 11 to nn. The root of the tree is a vertex number 11. A tree is a connected undirected graph with n−1n−1 edges. You are

CF1328E Tree Queries

CF1328E Tree Queries 应该还是比较妙的 题意 给你一个树,然后多次询问 每次询问给出一堆节点,问你是否能找到一个从根出发的链,是的对于给出的每个节点,都能找出链上的点,是的他们的距离小于等于\(1\) \(n\leq 2\cdot 10^5,m\leq 2\cdot 10^5,\sum k\leq 2\cdot 10^5\) 其中\(m\)是询问次数,\(k\)是每次给出的点数 首先,一个点要想符合题目的条件,无非有两种情况 一种是就在链上,这个好说 另一种是距离链上的点距离

CF-1328 E. Tree Queries

E. Tree Queries 题目链接 题意 给定一个树,每次询问一组点,问是否存在一条从根到某点的路径,使得该组点到该路径的最短距离不超过1 分析 从根到达某点的路径,如果覆盖到了某个点,那么一定会覆盖它的父亲(根除外),所以对组内的点替换成他们的父亲,问题转换为是否存在一条从根出发的路径覆盖所有的点.做法是将这些点按照深度从小到大排序,然后深度小的必须为深度大的的祖先 相邻两点求LCA即可,由于题目特殊性,前面的点和后面的点必须和根在一条直直的路径上,所以可以用欧拉序直接来判断是否可行 另

Codeforces 375D Tree and Queries(DFS序+莫队+树状数组)

题目链接  Tree and Queries 题目大意  给出一棵树和每个节点的颜色.每次询问vj, kj 你需要回答在以vj为根的子树中满足条件的的颜色数目, 条件:具有该颜色的节点数量至少为kj. (莫队居然可以过) 首先转DFS序,这样就变成了区间查询. 然后直接套用莫队,求出每次询问状态下的t[],t[k]表示当前区间内拥有k个节点的颜色数量. 然后统计t[k] + t[k + 1], ..., t[MAX]即可,这个过程用树状数组维护. #include <bits/stdc++.h>

CodeForces 375D Tree and Queries 莫队||DFS序

Tree and Queries 题意:有一颗以1号节点为根的树,每一个节点有一个自己的颜色,求出节点v的子数上颜色出现次数>=k的颜色种类. 题解:使用莫队处理这个问题,将树转变成DFS序区间,然后就是开一个数据记录下出现次数为k次的颜色数目,查询的时候直接返回这个数组中的对应的值就行了. 注意的就是记得将节点的颜色传递给dfs序对应位置的颜色. 这个忘记了找了好久的bug. 代码: 1 #include<bits/stdc++.h> 2 using namespace std; 3

codeforces 375D . Tree and Queries 启发式合并 || dfs序+莫队

题目链接 一个n个节点的树, 每一个节点有一个颜色, 1是根节点. m个询问, 每个询问给出u, k. 输出u的子树中出现次数大于等于k的颜色的数量. 启发式合并, 先将输入读进来, 然后dfs完一个节点就处理跟它有关的询问. 感觉不是很难, 然而.....WA了n次最后还是看的别人的代码 1 #include <iostream> 2 #include <vector> 3 #include <cstdio> 4 #include <cstring> 5

Codeforces Round #629 (Div. 3) E. Tree Queries(LCA)

https://codeforces.com/contest/1328/problem/E 题目所描述的是一棵树,题中已明示1为root结点. 题目可以转化为,是否存在一条路径,满足集合中的k个点到路径的距离小于等于1? 思路: 1.首先倍增离线预处理出结点深度,便于后续在线询问LCA 2.对于每次的询问,依次扫描k个点.对于集合中的u和v两点,每次我们求出u和v的LCA,计算u和v到LCA的距离,如果u和v到LCA的距离同时大于1,那么说明无法找到一条路径,使得u和v到该路径链的距离小于等于1