CF1328E 题解

CF1328E 题解

$\text{Description}$

给定一个以 $1$ 为根的有根树,每次询问给定 $k_i$ 个点,询问是否存在一条起点为根节点的链,使得这 $k_i$ 个点到链的最短距离都小于等于 $1$。

$n\le 2\times 10^5,\sum k\le 2\times 10^5$。

$\text{Solution}$

首先容易发现点和链的最短距离小于等于 $1$ 是等价于这条链经过其父亲的,所以我们先将每个点变为它的父亲,然后问题转换为了是否存在一条链经过 $k$ 点。

我们将这些点按照深度或者 dfs 序排序,然后用 dfs 序依次判断后一个点是否在前一个点的子树里即可。

$\text{Code}$
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include<bits/stdc++.h>
#define REG register
using namespace std;

const int Maxn=200005;

inline void read(int& x){
static char c;
while(!isdigit(c=getchar()));x=c^48;
while(isdigit(c=getchar()))x=(x*10)+(c^48);
}

int n,m,k;

struct Edge{int v,nxt;}ed[Maxn<<1];
int head[Maxn],cnt;
inline void adde(int u,int v){ed[++cnt]=(Edge){v,head[u]},head[u]=cnt;}
inline void add(int u,int v){adde(u,v),adde(v,u);}
#define FORE(i,now) for(REG int i=head[now];i;i=ed[i].nxt)

int fat[Maxn],siz[Maxn],dfn[Maxn],tot;

int que[Maxn];

inline bool cmp(int a,int b){return dfn[a]<dfn[b];}

void dfs(int now,int fa){
fat[now]=fa,dfn[now]=++tot,siz[now]=1;
FORE(i,now){
int v=ed[i].v;
if(v==fa) continue;
dfs(v,now);
siz[now]+=siz[v];
}
}

inline void Work(){
read(n),read(m);
for(REG int i=1;i<n;++i){int u,v;read(u),read(v),add(u,v);}
dfs(1,1);
while(m--){
read(k);
for(REG int i=1;i<=k;++i) read(que[i]),que[i]=fat[que[i]];
sort(que+1,que+k+1,cmp);
int flag=1;
for(REG int i=2;i<=k;++i)
if(dfn[que[i]]<dfn[que[i-1]]||dfn[que[i]]>dfn[que[i-1]]+siz[que[i-1]]-1){flag=0;break;}
if(flag) puts("YES");
else puts("NO");
}
getchar(),getchar();
}

int main(){Work();}
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×