您的位置:首页 > 其它

hdoj 2586 <LCA转RMQ算法--学习之路>

2016-08-04 10:30 393 查看
题目链接: hdoj 2586

思路:

先找一点作为起点通过DFS回溯记录每次DFS的点数(就是从根节点遍历所有点的去路和回来时的路)

用vis [  ] 数组记录每次走过的是哪一个点--

用D [ ] 来对应vis [ ] 数组上的点的深度(与根节点的距离)

用R [ ] 来记录每个点第一次出现的位置(两点的最初位置之间(含他们自身)的点中深度最小的点就是他们的最近祖先)

然后查找RMQ算法就可以查到最近祖先了---

样例:



我这个程序是让n当根节点--(因为这一题让1当根节点,,代码错的也会过--不便于学习新知识--(这题数据太弱))

看倒数第二行:回溯的顺序就是13-10-12-10-7------

最后一行就是回溯的每个位置的点的深度(用RMQ时,就是根据这个比较的)

倒数第四行是每个点第一次出现的位置--

比如求3和4的最近祖先时:

3第一次出现在8的位置,4是18的位置--然后我们在最后一行8-18中找最小的深度()

找到最小深度4--再看倒数第二行发现对应的是3----就是说明点3是3和4的最近祖先

回溯过程图:



代码上的中间值便于理解这个方法,所以就没有删除--

代码:

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
#define MA 420000
int n,m;
struct node{
int to,w,next;
}edge[MA*2];
int head[MA];
int D[MA];//深度
int R[MA];//每个点第一次出现的位置
int QM[MA][33];
int vis[MA*2],kp;//vis记录第i个位置的数
int dis[MA];
void bfs(int now,int fa,int chang)
{
dis[now]=chang;
for (int j=head[now];j!=-1;j=edge[j].next)
{
if (edge[j].to==fa) continue;
bfs(edge[j].to,now,chang+edge[j].w);
}
}
void DFS(int now,int fa,int deep)
{
D[kp]=deep;
R[now]=kp;
vis[kp++]=now;
for (int j=head[now];j!=-1;j=edge[j].next)
{
if (edge[j].to==fa) continue;
DFS(edge[j].to,now,deep+1);
D[kp]=deep;
vis[kp++]=now;
}
}
int main()
{
int t;scanf("%d",&t);
while (t--)
{
scanf("%d%d",&n,&m);
int a,b,c;
for (int i=1;i<=n;i++)
head[i]=-1;
for (int i=0;i<n-1;i++)
{
scanf("%d%d%d",&a,&b,&c);
edge[i*2].to=b;edge[i*2].w=c;
edge[i*2].next=head[a];
head[a]=i*2;
edge[i*2+1].to=a;edge[i*2+1].w=c;
edge[i*2+1].next=head[b];
head[b]=i*2+1;
}
kp=1;
bfs(n,-1,0);
DFS(n,-1,1);
/*	for (int i=1;i<=n;i++)
printf("%4d",i);printf("\n");
for (int i=1;i<=n;i++)
printf("%4d",R[i]);printf("\n");
for (int i=1;i<kp;i++)
printf("%4d",i);printf("\n");*/
for (int i=1;i<kp;i++)
{
//		printf("%4d",vis[i]);
QM[i][0]=i;
}
/*	printf("\n");
for (int i=1;i<kp;i++)
printf("%4d",D[i]);
printf("\n");*/
int nn=kp-1;
int p=log2(nn);
for (int i=1;i<=p;i++)
for (int j=1;j+(1<<i)-1<=nn;j++)
{
int aa=QM[j][i-1];
int bb=QM[j+(1<<(i-1))][i-1];
//		printf("%d   %d   %d   %d 66666666666\n",aa,bb,D[aa],D[bb]);
if (D[aa]<=D[bb])
QM[j][i]=aa;
else
QM[j][i]=bb;
//		printf("%d  %d  %d\n",j,i,QM[j][i]);
}
/*	printf("\n");
for (int i=1;i<=n;i++)
printf("%4d\n",dis[i]);
*/	while (m--)
{
scanf("%d%d",&a,&b);
int aa=min(R[a],R[b]);
int bb=max(R[a],R[b]);
//		printf("%d   %d     9999999999999\n",aa,bb);
int pp=log2(bb+1-aa);
int aaa=QM[aa][pp];
int bbb=QM[bb+1-(1<<pp)][pp];
//     c=min(QM[aa][pp],QM[bb+1-(1<<pp)][pp]);
//  		printf("%d   %d    666\n",aaa,bbb);
if (D[aaa]<=D[bbb])
c=aaa;
else
c=bbb;
//	    printf("%d\n",c);
c=vis[c];
//    printf("ans    :   %d\n",dis[a]+dis[b]-2*dis[c]);
printf("%d\n",dis[a]+dis[b]-2*dis[c]);
}
}
return 0;
}
/*2
13 13
1 2  1
1 3  1
1 4  1
3 5  1
3 6  1
3 7  1
6 8  1
6 9  1
7 10  1
7 11  1
10 12  1
10 13  1*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐