hdu 4297 One and One Story

Original link: http://www.cnblogs.com/liulangye/archive/2012/09/19/2694305.html

http://acm.hdu.edu.cn/showproblem.php?pid=4297

This title is a special FIG forest trees special in that it has a ring this ring node comprises a root

The basic idea:

First with disjoint-set processing of FIG.

1 establish a complete forest

2 sides that constitute the ring without the addition of forest

3 has the number of points recorded in each ring belonging to several points on each ring ring

Then deal with couples

Not a tree unreachable

With a special treatment in the room

The couples Storage

Here LCA LCA LCA and different from the original

If the most recent common ancestor does not ring if obtained directly seek it in the ring which are over a point on the ring

Finally, like processed

Selecting the optimum different schemes

Codes and their comments:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>

#define LL long long
//外挂开栈
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

const int N=500005;
vector<int>qtnum[N];//表示有此点 的couple 是第几个couple
vector<int>treehead;//每个数的树根
vector<int>cirnodenum;//一个树对应一个环 这个环的点个数
struct node1{
    int l,r;
    int lf,rf;
}qt[N];//couples l,r 如果公共最近父节点不在环上 lf,rf则相等 
      //否则对应表示从环上哪个点过来
int head[N];
struct node
{
    int j,next;
}side[N];//邻接表存森林
int I;
int f[N];//并查集使用
int pre[N];//每个点对应的前驱结点
int cir[N],T;//每个点对应第几个环 不在环上为 -1 T用来环计数
int dist[N];//每个点到树根的距离
int Findf(int x)
{
    if(x!=f[x])
    f[x]=Findf(f[x]);
    return f[x];
}
void Build(int i,int j)
{
    side[I].j=j;
    side[I].next=head[i];
    head[i]=I++;
}
void Findcir(int boot,int k)//求环内点个数 及环上点标记在第几个环上
{
    int sum=0;
    while(k!=boot){
        ++sum;
        cir[k]=T;
        k=pre[k];
    }
    ++sum;
    cirnodenum.push_back(sum);
    cir[k]=T++;
}
void Searchqt(int l,int k)//找 couples 的lf 和 rf
{
    for(unsigned int i=0;i<qtnum[l].size();++i)
    {
        int j=qtnum[l][i];
        if(l==qt[j].l)
        {
            if(f[qt[j].r]!=-1)
            {
                int ftemp=Findf(qt[j].r);
                if(cir[ftemp]!=-1)qt[j].lf=k;
                else qt[j].lf=ftemp;
                qt[j].rf=ftemp;
            }
        }else
        {
            if(f[qt[j].l]!=-1)
            {
                int ftemp=Findf(qt[j].l);
                if(cir[ftemp]!=-1)qt[j].rf=k;
                else qt[j].rf=ftemp;
                qt[j].lf=ftemp;
            }
        }
    }
}
void dfs(int x,int pre,int k,int d)//LCA
{
    dist[x]=d;
    if(cir[x]!=-1)//从环上哪个点上过来 如果此点在环上 更新
    k=x;
    Searchqt(x,k);
    f[x]=x;
    for(int t=head[x];t!=-1;t=side[t].next)
    {
        int l=side[t].j;
        dfs(l,x,k,d+1);
    }
    if(cir[x]==-1)//环上的点不在想前指向
    f[x]=pre;
}
void Lca()
{
    memset(f,-1,sizeof(f));
    for(unsigned int i=0;i<treehead.size();++i)
    dfs(treehead[i],treehead[i],-1,0);
}
int main()
{
    //freopen("data.txt","r",stdin);
    int n,K;
    while(scanf("%d %d",&n,&K)!=EOF)
    {
        memset(head,-1,sizeof(head));
        memset(cir,-1,sizeof(cir));
        I=0;T=0;
        for(int i=1;i<=n;++i)
        {f[i]=i;qtnum[i].clear();}
        treehead.clear();cirnodenum.clear();
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&pre[i]);
            if(Findf(i)!=Findf(pre[i]))//是否有环
            {
                f[Findf(i)]=Findf(pre[i]);
                Build(pre[i],i);
            }
            else
            {
                Findcir(i,pre[i]);//有环的话 就记录相关信息
                treehead.push_back(i);
            }
        }
        for(int i=0;i<K;++i)//对couples 进行取舍 处理记录
        {
            scanf("%d %d",&qt[i].l,&qt[i].r);
            if(Findf(qt[i].l)!=Findf(qt[i].r))
            {qt[i].lf=qt[i].rf=-1;continue;}
            if(qt[i].l==qt[i].r)
            {qt[i].lf=qt[i].rf=0;continue;}
            if(cir[qt[i].l]!=-1&&cir[qt[i].r]!=-1)
            {qt[i].lf=qt[i].l;qt[i].rf=qt[i].r;continue;}
            qtnum[qt[i].l].push_back(i);
            qtnum[qt[i].r].push_back(i);
        }
        Lca();
        int ansa,ansb,A,B,atemp,btemp;
        int maxa,maxb,mina,minb;
        for(int i=0;i<K;++i)//找各种方案最优
        {
            if(qt[i].lf<=0)
            {printf("%d %d\n",qt[i].lf,qt[i].rf);continue;}
            A=dist[qt[i].l]-dist[qt[i].lf];
            B=dist[qt[i].r]-dist[qt[i].rf];
            if(qt[i].lf==qt[i].rf)
            {printf("%d %d\n",A,B);continue;}
            atemp=dist[qt[i].lf]-dist[qt[i].rf];
            if(atemp<0)atemp+=cirnodenum[cir[qt[i].lf]];
            btemp=dist[qt[i].rf]-dist[qt[i].lf];
            if(btemp<0)btemp+=cirnodenum[cir[qt[i].rf]];
            maxa=max(A+atemp,B);
            maxb=max(A,B+btemp);
            mina=min(A+atemp,B);
            minb=min(A,B+btemp);
            if(maxa<maxb||(maxa==maxb&&(mina<minb||(mina==minb&&A+atemp>=B))))
            {ansa=A+atemp;ansb=B;}
            else
            {ansa=A;ansb=B+btemp;}
            printf("%d %d\n",ansa,ansb);
        }
    }
    return 0;
}

 

Reproduced in: https: //www.cnblogs.com/liulangye/archive/2012/09/19/2694305.html

Guess you like

Origin blog.csdn.net/weixin_30563917/article/details/94791697
one
ONE