您的位置:首页 > 其它

poj 1986(离线查询点对最近公共祖先)

2015-12-21 11:19 323 查看
题意:给一棵树,查询一些点对的距离

解法:随便找一个点建立有根树,然后转化为求点对最近公共祖先问题。两点的距离等于他们与最近祖先的距离和。查询的方法是dfs+并查集离线查询。思想是,dfs过的为回溯的点的parent全部指向自己本身,vis标记为true。回溯之后的点parent指向自己的父亲。然后dfs每进入一个点,就处理这个点相关的查询,如果其中某个查询另一个点v的vis为true,那么它们俩的最近公共祖先就是并查集中v的最终祖先。

代码:

#include <cstring>
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
int n,m;
const int Max=100100;
struct edge
{
int v;
int ran;
int next;
} edges[Max*2];
int head[Max];
int parent[Max];
int dis[Max];
int ans[Max];
int count1=0;
vector<pair<int,int> > vec[Max];
bool vis[Max];
int getparent(int u)
{
if(u==parent[u])
return u;
return parent[u]=getparent(parent[u]);
}
void add(int u,int v,int dis)
{
vec[u].push_back(make_pair(v,dis));
vec[v].push_back(make_pair(u,dis));
}
void addedge(int u,int v,int r)
{
edges[count1].v=v;
edges[count1].ran=r;
edges[count1].next=head[u];
head[u]=count1++;
}
bool dfs(int u,int d)
{
if(vis[u])
return false;
vis[u]=1;
dis[u]=d;
parent[u]=u;
for(int i=head[u]; i!=-1; i=edges[i].next)
{
int v=edges[i].v;
if(vis[v])
{
int p=getparent(v);
ans[edges[i].ran]=dis[u]+dis[v]-2*dis[p];
}
}
for(int i=0; i<vec[u].size(); i++)
{
if(dfs(vec[u][i].first,d+vec[u][i].second))
parent[vec[u][i].first]=u;
}
return true;
}
int main()
{
cin>>n>>m;
memset(head,-1,sizeof head);
memset(vis,0,sizeof vis);
for(int i=0; i<m; i++)
{
int a,b,c;
char r;
scanf("%d%d%d",&a,&b,&c);
cin>>r;
add(a,b,c);
add(b,a,c);
}
int k;
cin>>k;
for(int i=0; i<k; i++)
{
int a,b;
cin>>a>>b;
addedge(a,b,i);
addedge(b,a,i);
}
dfs(1,0);
for(int i=0; i<k; i++)
cout<<ans[i]<<"\n";
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: