Sample Input
Sample Output
2<=N<=10,000.
2 16 1 14 8 5 10 16 5 9 4 6 8 4 4 10 1 13 6 15 10 11 6 7 10 2 16 3 8 1 16 12 16 7 5 2 3 3 4 3 1 1 5 3 5
4 3
题意:T组数据,n个点,n-1条边,最后一组查询公共祖先
题解:本题只有一组查询,暴力复杂度:N*1,可用
暴力代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxm=10005;
int father[maxm];
bool vis[maxm];
int main()
{
int n,i,j,k,sum,a,b,t,x,y;
scanf("%d",&t);
while(t--)
{
memset(vis,false,sizeof(vis));
memset(father,-1,sizeof(father));
scanf("%d",&n);
for(i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
father[y]=x;
}
scanf("%d%d",&a,&b);
while(b!=-1)
{
vis[b]=true;
b=father[b];
}
while(!vis[a])
a=father[a];
printf("%d\n",a);
}
return 0;
}
Tarjan代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#define N 10006
using namespace std;
int in[N],par[N],vis[N],n;
vector<int>q[N],que[N];
int F(int x)
{
return par[x]==x?x:par[x]=F(par[x]);
}
void Tarjan(int rf)
{
int i,rz;
par[rf]=rf;//自成一个集合
rz=q[rf].size();
for(i=0; i<rz; i++)//从0循环
{
Tarjan(q[rf][i]);//向下遍历每个节点
par[q[rf][i]]=rf;
}
vis[rf]=1;
rz=que[rf].size();
for(i=0; i<rz; i++)
{
if(vis[que[rf][i]]==1)
{
printf("%d\n",F(que[rf][i]));//仅这一处认老祖宗
//仅一组查询可以加return,多组不可加!
}
}
}
int main()
{
int t,i,a,b;
cin>>t;
while(t--)
{
scanf("%d",&n);
for(i=1; i<=n; i++)
{
in[i]=vis[i]=0;
q[i].clear();
que[i].clear();
}
for(i=1; i<n; i++)
{
scanf("%d%d",&a,&b);
q[a].push_back(b);//a到b有一条单向边
in[b]=1;//入度
}
scanf("%d%d",&a,&b);
que[a].push_back(b);
que[b].push_back(a);//查询队列里a->b,b->a都要写
for(i=1; i<=n; i++)
if(in[i]==0)
break;
Tarjan(i);
}
return 0;
}
参考博客Tarjan讲解:http://www.cnblogs.com/JVxie/p/4854719.html