您的位置:首页 > 其它

【LCA/tarjan】POJ1470-Closest Common Ancestors

2016-08-12 17:06 531 查看
【题意】

给出一棵树和多组查询,求以每个节点为LCA的查询数有多少?

【错误点】

①读入的时候,注意它的空格是随意的呀!一开始不知道怎么弄,后来看了DISCUSS区大神的话:


询问部分输入:

scanf("%d",&m);
for(int i=0;i<m;i++){
scanf(" (%d %d)",&a,&b);
}

注意scanf(" 这里有一个空格


②多组数据啊!注意这句话:
The input file contents several data sets (at least one).

③痛心疾首!它问的是以每个节点为LCA的查询数,所以查询可以重复,同样的查询可以累计!

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int MAXN=900+5;
vector<int> E[MAXN];
int query[MAXN][MAXN];
int cnt[MAXN];
int notrt[MAXN],rt;
int ance[MAXN];
int vis[MAXN];
int m;//结点的总个数

int find(int u)
{
int r=u;
while (ance[r]!=r) r=ance[r];
int ans=r;
r=u;
while (ance[r]!=r)
{
int tmp=ance[r];
ance[r]=ans;
r=tmp;
}
return ans;
}

void tarjan(int u)
{
vis[u]=1;
for (int v=1;v<=m;v++)
{
if (!query[u][v]) continue;
if (vis[v])
//被访问过有两种情况:一是祖先靠左的子树中的后代;或者是自己的祖先。两者的LCA均为v所在并查集的根
{
int LCA=find(v);
cnt[LCA]+=query[u][v];
//注意,允许同样的查询出现多次,并且同样的查询可以累计!
}
}

ance[u]=u;
for (int i=0;i<E[u].size();i++)
{
int v=E[u][i];
tarjan(v);
ance[v]=u;
}
}

void init()
{
memset(query,0,sizeof(query));
memset(cnt,0,sizeof(cnt));
memset(notrt,0,sizeof(notrt));
memset(vis,0,sizeof(vis));
for (int i=1;i<=m;i++) E[i].clear();
for (int i=0;i<m;i++)
{
int p,T;
scanf("%d:(%d)",&p,&T);
for (int i=0;i<T;i++)
{
int son;
scanf(" %d",&son);
E[p].push_back(son);
notrt[son]++;
}
}

int n;
scanf("%d",&n);
for (int i=0; i<n; i++)
{
int a,b;
scanf(" (%d %d)",&a,&b);
//注意这里(前面要有一个空格!否则无法过!
query[a][b]++;
query[b][a]++;
}

for (int i=1;i<=m;i++) if (!notrt[i])
{
rt=i;
break;
}
}

void print()
{
for (int i=1;i<=m;i++)
if (cnt[i]>0)
cout<<i<<':'<<cnt[i]<<endl;
}

int main()
{
while (~scanf("%d",&m))
//注意是多组数据
{
init();
tarjan(rt);
print();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: