标签:lca def space turn 三个点 lse == memset get
如果题目中只有两个国家,事情就非常简单了:假设只有国家\(A\)和\(B\),我们先找出\(A\)和\(B\)的最近公共祖先\(lca\),然后找到在路径\(A\longrightarrow lca\longrightarrow B\)上的中点\(mid\),然后分3类讨论:
若\(dis(A,mid)==dis(B,mid)\),则\(A\)在这条路径上能到达的范围是\([A,mid)\),\(B\)在这条路径上能到达的范围是\((mid,B]\)。那么\(A\)在全树所能到达的点数为:
\[ \begin{cases} size[son] & \text{if }deep[A]>deep[B] & (son=在路径[mid,A]上的mid的儿子)\ n-size[mid] & \text{if }deep[B]>deep[A] \end{cases}\]
\(B\)在全树能到达的点数为:
\[ \begin{cases} n-size[mid] & \text{if }deep[A]>deep[B]\ size[son] & \text{if }deep[B]>deep[A] & (son=在路径[mid,B]上的mid的儿子) \end{cases} \]
若\(dis(A,mid)<dis(B,mid)\),则\(A\)在这条路径上能到达的范围是\([A,mid]\),\(B\)在这条路径上能到达的范围是\((mid,B]\)。那么\(A\)在全树所能到达的点数为:
\[ \begin{cases} size[mid] & \text{if }deep[A]>deep[B]\ n-size[son] & \text{if }deep[B]>deep[A] & (son=在路径[mid,B]上的mid的儿子) \end{cases}\]
\(B\)在全树能到达的点数为:
\[ \begin{cases} n-size[mid] & \text{if }deep[A]>deep[B]\ size[son] & \text{if }deep[B]>deep[A] & (son=在路径[mid,B]上的mid的儿子) \end{cases} \]
若\(dis(A,mid)>dis(B,mid)\),那就把\(A\)、\(B\)交换一下就和情况2一样了。
那么对于三个点的情况,只需对于每个点求出与另外两个点所能到的范围,再取并集就好了。
代码如下:
#include<bits/stdc++.h>
#define N 100010
#define LN 18
using namespace std;
struct data
{
bool opt;
int u;
data(){};
data(bool a,int b){opt=a,u=b;}
};
int t,n,m;
int cnt,head[N],nxt[N<<1],to[N<<1];
int fa[N][LN],d[N],size[N];
void init()
{
cnt=0;
memset(head,0,sizeof(head));
}
void adde(int u,int v)
{
to[++cnt]=v;
nxt[cnt]=head[u];
head[u]=cnt;
}
void dfs(int u)
{
size[u]=1;
for(int i=1;i<=17;i++)
fa[u][i]=fa[fa[u][i-1]][i-1];
for(int i=head[u];i;i=nxt[i])
{
if(to[i]!=fa[u][0])
{
d[to[i]]=d[u]+1;
fa[to[i]][0]=u;
dfs(to[i]);
size[u]+=size[to[i]];
}
}
}
int lca(int a,int b)
{
if(d[a]<d[b])
swap(a,b);
for(int i=17;i>=0;i--)
if(d[fa[a][i]]>=d[b])
a=fa[a][i];
if(a==b)
return a;
for(int i=17;i>=0;i--)
if(fa[a][i]!=fa[b][i])
a=fa[a][i],b=fa[b][i];
return fa[a][0];
}
int up(int u,int d)
{
for(int i=17;i>=0;i--)
if(d>=(1<<i))
u=fa[u][i],d-=(1<<i);
return u;
}
data getmid(int x,int y,int lca)
{
int len=d[x]+d[y]-(d[lca]<<1);
if(d[x]>=d[y]) return data(0,up(x,(len-1)>>1));
return data(1,up(y,len>>1));
}
int query(int x,int y,int z,int xy,int xz)
{
data ans1=getmid(x,y,xy),ans2=getmid(x,z,xz);
if(!ans1.opt&&!ans2.opt)
{
if(d[ans1.u]<d[ans2.u])
swap(ans1,ans2);
return size[ans1.u];
}
else
{
if(ans1.opt&&ans2.opt)
{
if(d[ans1.u]<d[ans2.u])
swap(ans1,ans2);
if(lca(ans1.u,ans2.u)==ans2.u)
return n-size[ans2.u];
return n-size[ans2.u]-size[ans1.u];
}
else
{
if(ans1.opt)
swap(ans1,ans2);
if(lca(ans1.u,ans2.u)==ans1.u)
return size[ans1.u]-size[ans2.u];
return size[ans1.u];
}
}
}
int main()
{
scanf("%d",&t);
while(t--)
{
init();
scanf("%d",&n);
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
adde(u,v),adde(v,u);
}
d[1]=1;
dfs(1);
scanf("%d",&m);
while(m--)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
int xy=lca(x,y),xz=lca(x,z),yz=lca(y,z);
printf("%d %d %d\n",query(x,y,z,xy,xz),query(y,x,z,xy,yz),query(z,x,y,xz,yz));
}
}
return 0;
}
标签:lca def space turn 三个点 lse == memset get
原文地址:https://www.cnblogs.com/ez-lcw/p/11617164.html