CodeForces 1328E-Tree QueriesLCA
Posted 1024-xzx
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CodeForces 1328E-Tree QueriesLCA相关的知识,希望对你有一定的参考价值。
题意:
??给出一棵 (n) 个点的树,(m) 次询问,每次询问给出 (k) 个点,问这 (k) 个点能否在其中某个点到根节点 (1) 的路径上或者与路径的距离为 (1)。
数据范围:(2≤n≤2?10^{5}) , (1≤m≤2?10^{5}) , (1≤k_i≤n) , (sum_{i=1}^{m}{k_i}≤2?10^5)
分析:
??首先,要确定路径。显然,应该为深度最深的点到根节点的路径。然后,在判断其他的点是否满足要求。
??一开始的做法是,把第 (i) 询问中的每个点累加到其父亲节点上,然后把路径跑一遍,再剪一下枝,但最后 (t)在了第 (100) 个测试点。
??可能是因为树的形态导致,很可能每次查询的复杂度都是 (O(n))。
代码如下:
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
typedef pair<int,int>P;
const int N=2e5+5;
vector<int>pic[N];
int depth[N],par[N],vis[N];
P num[N];
void read(int &x)
{
x=0;
int f=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch==‘-‘)
f=-1;
ch=getchar();
}
while(isdigit(ch))
{
x=(x<<3)+(x<<1)+ch-‘0‘;
ch=getchar();
}
x*=f;
}
void dfs(int v,int p,int d)
{
depth[v]=d;
par[v]=p;
for(int i=0;i<pic[v].size();i++)
{
int u=pic[v][i];
if(u!=p)
dfs(u,v,d+1);
}
}
int main()
{
int n,m,u,v,k,p;
read(n),read(m);
for(int i=1;i<n;i++)
{
read(u),read(v);
pic[u].pb(v);
pic[v].pb(u);
}
dfs(1,0,0);
for(int i=1;i<=m;i++)
{
read(k);
int maxn=-1,minn=n+1;
for(int j=1;j<=k;j++)
{
read(v);
vis[v]=i;
if(depth[v]>maxn)
{
maxn=depth[v];
p=v;
}
minn=min(minn,depth[par[v]]);
if(num[par[v]].first!=i)
{
num[par[v]].first=i;
num[par[v]].second=0;
}
num[par[v]].second++;
}
int last=n+1;
while(p)
{
if(k==0||depth[p]<minn)
break;
if(vis[p]==i)
k--;
if(num[p].first==i)
k-=num[p].second;
if(vis[last]==i)
k++;
last=p;
p=par[p];
}
if(k==0)
printf("YES
");
else
printf("NO
");
}
return 0;
}
??因此,要借助 (lca) 来解决。 假设深度最深的点为点 (p) ,对于另一个点 (x) ,要使其满足要求,那么 (lca(p,x)=x),要么 (lca(p,x)=x) 的父亲节点。
??这样的复杂度就比较稳定,为 (O(mlogn))。
代码:
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
const int N=2e5+5;
const int mak=20;
vector<int>pic[N];
int depth[N],par[N][mak],vn[N];
void read(int &x)
{
x=0;
int f=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch==‘-‘)
f=-1;
ch=getchar();
}
while(isdigit(ch))
{
x=(x<<3)+(x<<1)+ch-‘0‘;
ch=getchar();
}
x*=f;
}
void dfs(int v,int p,int d)
{
depth[v]=d;
par[v][0]=p;
for(int i=0;i<pic[v].size();i++)
{
int u=pic[v][i];
if(u!=p)
dfs(u,v,d+1);
}
}
void init(int n)
{
dfs(1,0,0);
for(int k=0;k+1<mak;k++)
{
for(int i=1;i<=n;i++)
par[i][k+1]=par[par[i][k]][k];
}
}
int lca(int u,int v)
{
if(depth[u]>depth[v])
swap(u,v);
for(int k=0;k<mak;k++)
{
if((depth[v]-depth[u])>>k&1)
v=par[v][k];
}
if(u==v)
return u;
for(int k=mak-1;k>=0;k--)
{
if(par[u][k]!=par[v][k])
{
u=par[u][k];
v=par[v][k];
}
}
return par[u][0];
}
int main()
{
int n,m,u,v;
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
pic[u].pb(v);
pic[v].pb(u);
}
init(n);
while(m--)
{
int k=0,p,maxn=-1;
scanf("%d",&k);
for(int i=1;i<=k;i++)
{
scanf("%d",&vn[i]);
if(depth[vn[i]]>maxn)
{
maxn=depth[vn[i]];
p=vn[i];
}
}
bool f=1;
for(int i=1;i<=k;i++)
{
int t=lca(p,vn[i]);
if(t!=vn[i]&&par[vn[i]][0]!=t)
{
f=0;
break;
}
}
if(f)
printf("YES
");
else
printf("NO
");
}
return 0;
}
以上是关于CodeForces 1328E-Tree QueriesLCA的主要内容,如果未能解决你的问题,请参考以下文章
CF1328E-Tree Queries(补) (dfs序)
=Tree Queries CodeForces - 1328E (LCA+思维)