poj 1330 LCA问题 (LCA问题转化为RMQ || tarjan算法)

LCA问题可以与RMQ问题互相转化,长郡中学 郭华阳的《RMQ&LCA问题》讲的很好。

这个博客也讲的很好:http://dongxicheng.org/structure/lca-rmq/

Run ID User Problem Result Memory Time Language Code Length Submit Time
10873609 xinghan0219 1330 Accepted 3176K 47MS G++ 2000B 2012-10-01 19:49:03
10546730 xinghan0219 1330 Accepted 2032K 63MS G++ 1756B 2012-07-27 17:08:33

RMQ问题:http://www.cnblogs.com/Missa/archive/2012/10/01/2709686.html

tarjan算法模版:http://www.cnblogs.com/Missa/archive/2012/10/01/2709749.html

RMQ+dfs:

  1 #include <iostream>

  2 #include <cstdio>

  3 #include <cstring>

  4 #include <cmath>

  5 

  6 using namespace std;

  7 

  8 #define MAXN 10005

  9 #define MAXM 105

 10 #define inf 0x7ffffff

 11 int n;

 12 struct Edge

 13 {

 14     int v,next;

 15 }edge[MAXN];

 16 int head[MAXN];

 17 int e;

 18 

 19 void clear()//初始化

 20 {

 21     memset(head,-1,sizeof(head));

 22     e=0;

 23 }

 24 void addEdge(int u,int v)//加边

 25 {

 26     edge[e].v=v;

 27     edge[e].next=head[u];head[u]=e++;

 28 }

 29 int first[MAXN];//结点在搜索顺序数组中最先出现的位置(下标)

 30 int occur[MAXN<<1];//结点在出现的顺序数组重复的也要记录

 31 int depth[MAXN<<1];//结点在搜索树中的深度,与occur相对应

 32 int dp_min[MAXN<<1][20];//dp_min[i][j] 表示从第i个位置开始的2^j个元素中的最小值的下标

 33 int m=0;//不断记录出现的下标

 34 

 35 void dfs(int u,int deep)

 36 {

 37     occur[++m]=u;//进入该点时进行记录

 38     depth[m]=deep;

 39     if(!first[u])

 40         first[u]=m;

 41     for(int i=head[u];i+1;i=edge[i].next)

 42     {

 43         dfs(edge[i].v,deep+1);

 44         occur[++m]=u;//访问子树返回也要标记

 45         depth[m]=deep;

 46     }

 47 }

 48 void init()

 49 {

 50     clear();

 51     m=0;

 52     memset(first,0,sizeof(first));

 53     bool in[MAXN];//记录结点有无入度

 54     memset(in,false,sizeof(in));

 55     int u=0,v=0;

 56     scanf("%d",&n);

 57     for(int i=1;i<n;i++)//注意此题只有n-1条边

 58     {

 59         scanf("%d%d",&u,&v);

 60         addEdge(u,v);//u->v单向

 61         in[v]=true;

 62     }

 63     for(int i=1;i<=n;i++)//从根开始dfs

 64     {

 65         if(!in[i])

 66         {

 67             dfs(i,0);

 68             break;

 69         }

 70     }

 71 }

 72 

 73 void RMQ_init(int num)

 74 {

 75     for(int i=1;i<=num;i++)

 76         dp_min[i][0]=i;//注意dp_min存的不是最小值,而是最小值的下标

 77     for(int j=1;j<20;j++)

 78         for(int i=1;i<=num;i++)

 79         {

 80             if(i+(1<<j)-1 <= num)

 81             {

 82                 dp_min[i][j] = depth[dp_min[i][j-1]] < depth[dp_min[i+(1<<(j-1))][j-1]] ? dp_min[i][j-1] : dp_min[i+(1<<(j-1))][j-1];

 83             }

 84         }

 85 }

 86 

 87 int RMQ_min(int a,int b)

 88 {

 89     int l=first[a],r=first[b];//得到区间左右端点

 90     if(l>r)

 91     {

 92         int t=l;

 93         l=r;

 94         r=t;

 95     }

 96     int k=(int)(log(double(r-l+1))/log(2.0));

 97     int min_id=depth[dp_min[l][k]]<depth[dp_min[r-(1<<k)+1][k]]?dp_min[l][k]:dp_min[r-(1<<k)+1][k];//最小值下标

 98     return occur[min_id];//取得当前下标表示的结点

 99 }

100 

101 int main()

102 {

103     int t;

104     int a,b;

105     scanf("%d",&t);

106     while(t--)

107     {

108         init();

109         RMQ_init(m);

110         scanf("%d%d",&a,&b);

111         printf("%d\n",RMQ_min(a,b));

112     }

113     return 0;

114 }

tarjan算法:

  1 //O(n+Q)

  2 

  3 #include <iostream>

  4 #include <cstdio>

  5 #include <cstring>

  6 #include <vector>

  7 

  8 using namespace std;

  9 

 10 #define MAXN 10001

 11 

 12 int n,fa[MAXN];

 13 int rank[MAXN];

 14 int indegree[MAXN];

 15 int vis[MAXN];

 16 vector<int> hash[MAXN],Qes[MAXN];

 17 int ances[MAXN];//祖先

 18 

 19 

 20 void init(int n)

 21 {

 22     for(int i=0;i<=n;i++)

 23     {

 24         fa[i]=i;

 25         rank[i]=0;

 26         indegree[i]=0;

 27         vis[i]=0;

 28         ances[i]=0;

 29         hash[i].clear();

 30         Qes[i].clear();

 31     }

 32 }

 33 

 34 int find(int x)

 35 {

 36     if(x != fa[x])

 37         fa[x]=find(fa[x]);

 38     return fa[x];

 39 }

 40 

 41 void unio(int x,int y)

 42 {

 43     int fx=find(x),fy=find(y);

 44     if(fx==fy) return ;

 45     if(rank[fy]<rank[fx])

 46         fa[fy]=fx;

 47     else

 48     {

 49         fa[fx]=fy;

 50         if(rank[fx]==rank[fy])

 51             rank[fy]++;

 52     }

 53 }

 54 

 55 void Tarjan(int u)

 56 {

 57     ances[u]=u;

 58     int i,size = hash[u].size();

 59     for(i=0;i<size;i++)

 60     {

 61         Tarjan(hash[u][i]);//递归处理儿子

 62         unio(u,hash[u][i]);//将儿子父亲合并,合并时会将儿子的父亲改为u

 63         ances[find(u)]=u;//此时find(u)仍为u,即

 64     }

 65     vis[u]=1;

 66     

 67     //查询

 68     size = Qes[u].size();

 69     for(i=0;i<size;i++)

 70     {

 71         if(vis[Qes[u][i]]==1)//即查询的另一个结点开始已经访问过,当前的u在此回合访问。

 72         {

 73             printf("%d\n",ances[find(Qes[u][i])]);//由于递归,此时还是在u

 74             return;

 75         }

 76     }

 77 }

 78 

 79 int main()

 80 {

 81     int t;

 82     int i,j;

 83     scanf("%d",&t);

 84     while(t--)

 85     {

 86         scanf("%d",&n);

 87         init(n);

 88         int s,d;

 89         for(i=1;i<=n-1;i++)

 90         {

 91             scanf("%d%d",&s,&d);

 92             hash[s].push_back(d);

 93             indegree[d]++;

 94         }

 95         scanf("%d%d",&s,&d);

 96         Qes[s].push_back(d);

 97         Qes[d].push_back(s);

 98         for(j=1;j<=n;j++)

 99         {

100             if(indegree[j]==0)

101             {

102                 Tarjan(j);

103                 break;

104             }

105         }

106     }

107     return 0;

108 }

你可能感兴趣的:(tar)