procedure2012
It's not worth it to know you're not worth it!

[关键字]:LCA

[题目大意]:求出一个集合点使树中三个点到这个点距离总和最小

//=============================================================

[分析]:无论怎么建树,这个集合点一定在这三个点两两的LCA之间,所以就转化成求LCA的问题,但这道题用离线的tarjan算法十分麻烦,所以就用的LCA转RMQ的在线算法。自我感觉代码写的相当给力:非递归+STL,可惜MLE……

[代码]:

View Code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stack>
#include<cmath>
using namespace std;

const int MAXN=500005;
const int INF=0x7fffffff;

int n,m,ans,pos;
int E[MAXN*2],R[MAXN],D[MAXN];
int f[MAXN*2][20],d[MAXN*2][20];
stack<int> s;
vector<int> e[MAXN];
vector<int>::iterator first[MAXN];

void Init()
{
int i,x,y;
scanf("%d%d",&n,&m);
for (i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
e[x].push_back(y);
e[y].push_back(x);
}
for (i=1;i<=n;i++) first[i]=e[i].begin();
}

void DFS()
{
s.push(1);
E[++E[0]]=1;
R[1]=1,D[1]=0;
while (!s.empty())
{
int u=s.top();
vector<int>::iterator i;
for (i=first[u];i!=e[u].end();++i)
if (!R[*i])
{
s.push(*i);
D[*i]=D[u]+1;
E[++E[0]]=*i;
R[*i]=E[0];
first[u]=i+1;
break;
}
if (i==e[u].end())
{
s.pop();
if (!s.empty()) E[++E[0]]=s.top();
}
}
/* printf("%d\n",E[0]);
for (int i=1;i<=E[0];++i) printf("%d ",E[i]);
printf("\n");
for (int i=1;i<=n;++i)
printf("%d\n",R[i]);
*/
}

void RMQ()
{
int len=(int)floor(log((double)E[0])/log(2.0));
for (int i=1;i<=E[0];++i)
f[i][0]=D[E[i]],d[i][0]=E[i];
for (int j=1;j<=len;++j)
for (int i=1;i<=E[0]-(1<<j)+1;++i)
if (f[i][j-1]<f[i+(1<<(j-1))][j-1])
f[i][j]=f[i][j-1],d[i][j]=d[i][j-1];
else
f[i][j]=f[i+(1<<(j-1))][j-1],d[i][j]=d[i+(1<<(j-1))][j-1];
}

int Find(int x,int y)
{
if (x>y) swap(x,y);
int len=(int)floor(log((double)y-x+1)/log(2.0));
if (f[x][len]<f[y-(1<<len)+1][len])
return d[x][len];
else
return d[y-(1<<len)+1][len];
}

void Work(int x,int y,int z)
{
int LCA=Find(R[x],R[y]);
int temp=D[x]+D[y]-2*D[LCA];
int lca=Find(R[LCA],R[z]);
temp+=D[LCA]+D[z]-2*D[lca];
if (ans>temp) ans=temp,pos=LCA;
}

void Solve()
{
int i,x,y,z;
for (i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
ans=INF;
Work(x,y,z);
Work(x,z,y);
Work(y,z,x);
printf("%d %d\n",pos,ans);
}
}

int main()
{
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
Init();
DFS();
RMQ();
Solve();
return 0;
}



posted on 2012-03-11 23:31  procedure2012  阅读(162)  评论(0编辑  收藏  举报