您的位置:首页 > 其它

poj 1330 树上LCA+RMQ

2011-04-23 23:28 260 查看
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
const int N = 10005;
const int M = 101;
const int MAX = 1000000000;
int n;
struct Edge
{
int u,v,next;
}edge
;
int head
,tot = 0;
void addedge(int u, int v)
{
tot++;
edge[tot].u = u;
edge[tot].v = v;
edge[tot].next = head[u];
head[u] = tot;
}
int first
;//结点在搜索顺序数组中最先出现的位置(下标)
int occur[2*N];//结点在出现的顺序数组重复的也要记录
int depth[2*N];//结点在搜索树中的深度,与occur相对应
int dp_min[2*N][20];//dp_min[i][j] 表示从第i个位置开始的2^j个元素中的最小值的下标
int m = 0;//不断记录出现的下标
void dfs(int u, int deep)
{
occur[++m] = u;//进入该点时进行记录
depth[m] = deep;
if(!first[u])
{
first[u] = m;
}
for(int i = head[u]; i != 0; i = edge[i].next)
{
dfs(edge[i].v, deep+1);
occur[++m] = u;//访问子树返回也要标记
depth[m] = deep;
}
}
void init()
{
tot = 0;
m = 0;
memset(head,0,sizeof(head));
memset(first,0,sizeof(first));
int in
= {false};//记录结点有无入度
memset(in,false,sizeof(in));
int u=0,v=0;
cin>>n;
for(int i = 1; i < n; i++)
{
cin>>u>>v;
addedge(u,v);//这里一定是u->v 否则要加双向边
in[v] = true;
}
for(int i = 1; i <= n; i++)//保证要从根开始dfs
{
if(!in[i])
{
dfs(i,1);
break;
}
}
}
void rmq_init()
{
for(int i = 1; i <= m; i++)
{
dp_min[i][0] = i;
}
for(int j = 1,s = 1; s <= m; s = (1<<(j++)))
{
for(int i = 1; i+s < m; i++)
{//由于要求的是最小值的下标这里采用间接比较,将长为s的区间分为相等的两端求最小值,以2的幂不断增加s,最终的解
dp_min[i][j] = depth[dp_min[i][j-1]] < depth[dp_min[i+s][j-1]] ? dp_min[i][j-1] : dp_min[i+s][j-1];
}
}
}
int rmq_min(int a, int b)
{
int l=first[a],r=first[b];//得到区间的左右端点
if(l > r)
{
int t = l;
l = r;
r = t;
}
int k = floor(log(double(r-l+1))/log(2.0));
int s = 1<<k;
int min_id = depth[dp_min[l][k]] < depth[dp_min[r-s+1][k]] ? dp_min[l][k] : dp_min[r-s+1][k];
return occur[min_id];
}
int main()
{
int t = 0;
int a = 0, b = 0;
cin>>t;
while(t--)
{
init();
rmq_init();
cin>>a>>b;
cout<<rmq_min(a,b)<<endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: