CF-1328 E. Tree Queries

E. Tree Queries

题目链接

题意

给定一个树,每次询问一组点,问是否存在一条从根到某点的路径,使得该组点到该路径的最短距离不超过1

分析

从根到达某点的路径,如果覆盖到了某个点,那么一定会覆盖它的父亲(根除外),所以对组内的点替换成他们的父亲,问题转换为是否存在一条从根出发的路径覆盖所有的点。做法是将这些点按照深度从小到大排序,然后深度小的必须为深度大的的祖先

相邻两点求LCA即可,由于题目特殊性,前面的点和后面的点必须和根在一条直直的路径上,所以可以用欧拉序直接来判断是否可行

另外求LCA的方法主要有四种,倍增,Tarjan离线,树剖,还有一种就是欧拉序上面RMQ

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
#define dbg(x...) do { cout << "\033[32;1m" << #x <<" -> "; err(x); } while (0)
void err() { cout << "\033[39;0m" << endl; }
template<class T, class... Ts> void err(const T& arg,const Ts&... args) { cout << arg << " "; err(args...); }
const int N = 200000 + 5;
int head[N], ver[N<<1], nxt[N<<1], tot;
int f[N][20], dep[N], a[N];
int n, m;
void add(int x, int y){
    ver[++tot] = y, nxt[tot] = head[x], head[x] = tot;
}
void dfs(int x, int fa){
    for(int i=head[x];i;i=nxt[i]){
        int y = ver[i];
        if(y == fa) continue;
        dep[y] = dep[x] + 1;
        f[y][0] = x;
        dfs(y, x);
    }
}
int lca(int x, int y){
    if(dep[x] > dep[y]) swap(x, y);
    for(int i=19;i>=0;i--) if(dep[f[y][i]] >= dep[x]) y = f[y][i];
    if(x == y) return x;
    for(int i=19;i>=0;i--) if(f[y][i] != f[x][i]) x = f[x][i], y = f[y][i];
    return f[x][0];
}
int main(){
    scanf("%d%d", &n, &m);
    for(int i=2;i<=n;i++){
        int x, y;
        scanf("%d%d", &x, &y);
        add(x, y);
        add(y, x);
    }
    dep[1] = 1;
    dfs(1, 0);
    for(int j=1;j<=19;j++){
        for(int i=1;i<=n;i++){
            f[i][j] = f[f[i][j-1]][j-1];
        }
    }
    while(m--){
        int k;scanf("%d", &k);
        for(int i=1;i<=k;i++){
            scanf("%d", &a[i]);
            a[i] = f[a[i]][0];
        }
        sort(a + 1, a + 1 + k, [](int x, int y)->bool{ return dep[x] < dep[y]; });
        bool flag = true;
        for(int i=2;i<=k;i++){
            if(lca(a[i-1], a[i]) != a[i-1]){
                flag = false;
                break;
            }
        }
        puts(flag ? "YES":"NO");
    }

    return 0;
}

原文地址:https://www.cnblogs.com/1625--H/p/12639920.html

时间: 2024-10-18 17:46:02

CF-1328 E. Tree Queries的相关文章

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

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]). 如果觉得很神

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\)是每次给出的点数 首先,一个点要想符合题目的条件,无非有两种情况 一种是就在链上,这个好说 另一种是距离链上的点距离

[SGU550]Tree Queries Online

题意:给一棵带边权的树,按给定的顺序删掉所有边,每删一条边,输出权值$w$,并把小的那块全部乘$w$,大的那块全部加$w$,强制在线 原题是sgu的,但现在sgu好像挂了,幸运地在codeforces gym里面找到这个题(题号是K) 本来这个并不是数据结构题,按题解的说法应该是用一些奇技淫巧转化一下,但为了好玩我还是写了个伪ETT练一下手 ETT全名是Euler Tour Tree,顾名思义就是用平衡树维护欧拉遍历序 对于这棵树,欧拉遍历序就是123242151,虽然它是一个环,但通常约定在根

CF 570 D. Tree Requests

D. Tree Requests http://codeforces.com/problemset/problem/570/D 题意: 一个以1为根的树,每个点上有一个字母(a-z),每次询问一个子树内深度为h的点是否可以构成回文串.(深度是到1的深度,没有也算,空回文串) 分析: dsu on tree.询问子树信息. 判断是否构成回文:出现奇数次的字符小于等于1个. 代码: 1 #include<cstdio> 2 #include<algorithm> 3 #include&

CF 1260F colored tree

点分治+线段树(过不去). 把点分治换成DSU ON THE TREE 应该就能过了. 设S为∏(R[i]-L[i]+1),W[i]为(R[i]-L[i]+1). 假设有一个点u,则它对答案的贡献为∑(disu + disv) * (S / (W[u] * W[v])),条件为u和v的区间有交. 把式子拆开有两个项,分别用线段树维护即可. #include<iostream> #include<cstdio> #include<algorithm> #include&l

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

CF 277E Binary Tree on Plane (拆点 + 费用流) (KM也可做)

题目大意: 平面上有n个点,两两不同.现在给出二叉树的定义,要求树边一定是从上指向下,即从y坐标大的点指向小的点,并且每个结点至多有两个儿子.现在让你求给出的这些点是否能构成一棵二叉树,如果能,使二叉树的树边长度(欧几里德长度)总和最小,输出这个总和.如果不能,输出-1.答案与标准答案相差1e-6内都认为是正确的. 算法讨论: 起初是这样想的,肯定是MCMF,费用是距离,然后流量一开始我是这样搞的:从父亲向儿子连流量为2的边.但是你会发现这样有一个问题,就是如果某个结点如果真的有两个儿子的话,那