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编辑  收藏  举报