卧薪尝胆,厚积薄发。
Adjacent Leaves
Date: Sun Feb 24 18:58:42 CST 2019 In Category: NoCategory

Description:

给出一棵树,每次问:如果以 $r$ 为根,能否通过合理安排每个点访问每个儿子的顺序,使得输入的集合 $S$ 里的叶子在 DFS 序中连续。
$1\leqslant n,\sum|S|\leqslant 5\times 10^5$

Solution:

首先肯定是建虚树,然后在虚树上 $dfs$ ,我们可以给每个点标一个状态:
0:所有叶子都被标记,记录子树内的标记点数和叶子个数。
1:叶子可以排成前后缀,子树内只能有0/1,并且1的个数小于等于1。
2:叶子可以排成连续区间,子树内只有0/1并且1的个数小于等于2或者子树内只有一个2。
3:不合法。
一个换根求 $LCA$ 的方法: $root=r,lca=lca(a,b)\text{ xor }lca(a,r)\text{ xor }lca(b,r)$ 。
然后还可以发现建虚树的时候 $dfn$ 可以换成 $dep$ ,也就可以用 $dis(a,b)$ 来求。
注意一个小细节,就是两个点在虚树上直接相连但是在原树上不直接相连,这条链伸出去的子树上可能还有叶子。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<vector>
#include<cctype>
#include<cstring>
using namespace std;
int n,q;
#define MAXN 500010
inline int rd()
{
register int res = 0,f = 1;register char c = getchar();
while(!isdigit(c)){if(c == '-')f = -1;c = getchar();}
while(isdigit(c))res = (res << 1) + (res << 3) + c - '0',c = getchar();
return res * f;
}
int deg[MAXN];
struct edge
{
int to,nxt;
}e[MAXN << 1];
int edgenum = 0;
int lin[MAXN] = {0};
void add(int a,int b)
{
++deg[a];++deg[b];
e[++edgenum] = (edge){b,lin[a]};lin[a] = edgenum;
e[++edgenum] = (edge){a,lin[b]};lin[b] = edgenum;
return;
}
int root;
int leaf[MAXN];
bool tag[MAXN];
int dfn[MAXN],tot = 0;
int f[MAXN][20];
int dep[MAXN];
void dfs(int k,int fa)
{
dep[k] = dep[fa] + 1;dfn[k] = ++tot;
for(int i = lin[k];i != 0;i = e[i].nxt)
{
if(e[i].to == fa)continue;
f[e[i].to][0] = k;
for(int x = 1;x <= 19;++x)f[e[i].to][x] = f[f[e[i].to][x - 1]][x - 1];
dfs(e[i].to,k);
leaf[k] += leaf[e[i].to];
}
return;
}
int skip_to_dep(int k,int d)
{
for(int i = 19;i >= 0;--i)if(dep[f[k][i]] >= d)k = f[k][i];
return k;
}
int LCA(int a,int b)
{
if(dep[a] < dep[b])swap(a,b);
a = skip_to_dep(a,dep[b]);
if(a == b)return a;
for(int i = 19;i >= 0;--i)
if(f[a][i] != f[b][i])a = f[a][i],b = f[b][i];
return f[a][0];
}
int LCA(int rt,int a,int b)
{
return LCA(a,b) ^ LCA(rt,a) ^ LCA(rt,b);
}
int dis(int a,int b)
{
return dep[a] + dep[b] - 2 * dep[LCA(a,b)] + 1;
}
int cntleaf(int rt,int k)
{
if(rt == root)return leaf[k];
if(k == rt)return leaf[root];
if(LCA(k,rt) != k)return leaf[k];
int son = skip_to_dep(rt,dep[k] + 1);
return leaf[root] - leaf[son];
}
int rt,v[MAXN];
int stack[MAXN],top = 0;
vector<int> g[MAXN];
bool cmp_dfn(int a,int b){return dfn[a] < dfn[b];}
void addv(int a,int b)
{//cout << a << " " << b << endl;
g[a].push_back(b);g[b].push_back(a);
return;
}
int siz[MAXN];
int nxtp(int k,int ano)
{
if(LCA(k,ano) != k)return f[k][0];
else return skip_to_dep(ano,dep[k] + 1);
}
int dp(int k,int fa)
{
siz[k] = tag[k];
int cnt[4] = {0};
int son = 0;
for(vector<int>::iterator it = g[k].begin();it != g[k].end();++it)
{
if(*it == fa)continue;
int val = dp(*it,k);
int nxt = nxtp(k,*it);//cout << k << " " << *it << " " << nxt << " : ";
if(val == 0 && cntleaf(rt,nxt) != cntleaf(rt,*it))val = 1;//cout << val << endl;
cnt[val]++;
siz[k] += siz[*it];
++son;
}
g[k].clear();
int res;
if(tag[k])res = 0;
else if(cnt[3])res = 3;
else if(siz[k] == cntleaf(rt,k))res = 0;
else if(cnt[2] == 0 && cnt[1] <= 1)res = 1;
else if((cnt[2] == 1 && son == 1) || (cnt[1] <= 2 && cnt[2] == 0))res = 2;
else res = 3;
//cout << k << " : " << res << endl;
return res;
}
void query()
{
scanf("%d%d",&rt,&v[0]);
for(int i = 1;i <= v[0];++i)scanf("%d",&v[i]);
v[++v[0]] = rt;
sort(v + 1,v + 1 + v[0],cmp_dfn);
top = 0;
stack[++top] = v[1];
for(int i = 2;i <= v[0];++i)
{
int lca = LCA(v[i],stack[top]);
if(lca == stack[top]){stack[++top] = v[i];continue;}
while(top >= 2)
{
if(dfn[lca] < dfn[stack[top - 1]])addv(stack[top - 1],stack[top]),--top;
else{addv(lca,stack[top]);--top;break;}
}
if(top == 1 && dfn[lca] < dfn[stack[top]])addv(lca,stack[top]),stack[top] = lca;
if(stack[top] != lca)stack[++top] = lca;
stack[++top] = v[i];
}
while(top >= 2)addv(stack[top - 1],stack[top]),--top;
if(dp(rt,0) != 3)puts("YES");
else puts("NO");
return;
}
int main()
{
scanf("%d%d",&n,&q);
for(int i = 1;i < n;++i)add(rd(),rd());
for(int i = 1;i <= n;++i)
{
if(deg[i] != 1)root = i;
else leaf[i] = 1,tag[i] = true;
}
dfs(root,0);
for(int i = 1;i <= q;++i)query();
return 0;
}
In tag: 树-虚树
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡