POJ 1986 Distance Queries 最近公共祖先
以前没见过“最近公共祖先”这一类的题啊。长见识了,呵呵。
解法基本上就是
http://www.cppblog.com/varg-vikernes/archive/2010/03/10/109355.html
这篇文章里面提到的两种方法。
两种方法的解法都非常精妙!
最后程序写出来:
Tarjan 3372K 219MS
DFS+RMQ 7992K 329MS
代码
Tarjan:
#include
<
stdio.h
>
#define MAX_N 40032
#define MAX_Q 10032
struct edge_node {
struct edge_node *next;
int idx, len;
} ;
struct edge_node edges[MAX_N * 2 ];
struct tree_node {
struct edge_node *edge;
struct query_node *query;
int depth, visited;
} ;
struct tree_node tree[MAX_N];
struct query_node {
int idx, ans;
struct query_node *next;
} ;
struct query_node queries[MAX_Q * 2 ];
struct set_node {
int parent, len;
} ;
struct set_node set [MAX_N];
__inline int max( int a, int b)
{
return a > b ? a : b;
}
__inline int find( int idx)
{
static int stack[MAX_N];
int i, sp;
for (sp = 0; set[idx].parent; sp++) {
stack[sp] = idx;
idx = set[idx].parent;
}
for (sp--; sp >= 0; sp--) {
i = stack[sp];
set[i].len += set[set[i].parent].len;
set[i].parent = idx;
}
return idx;
}
__inline void add_edge( int idx, int a, int b, int len)
{
struct edge_node *p = &edges[idx];
p->idx = b;
p->len = len;
p->next = tree[a].edge;
tree[a].edge = p;
}
__inline void add_query( int idx, int a, int b)
{
struct query_node *p = &queries[idx];
p->idx = b;
p->next = tree[a].query;
tree[a].query = p;
}
void dfs( int idx, int depth)
{
struct edge_node *e;
struct query_node *q;
int i;
tree[idx].visited = 1;
tree[idx].depth = depth;
for (q = tree[idx].query; q; q = q->next) {
if (!tree[q->idx].visited)
continue;
i = find(q->idx);
q->ans = tree[q->idx].depth + depth - 2*tree[i].depth;
}
for (e = tree[idx].edge; e; e = e->next) {
if (tree[e->idx].visited)
continue;
dfs(e->idx, depth + e->len);
set[e->idx].parent = idx;
set[e->idx].len = e->len;
}
}
int main()
{
int n, m, k, i, a, b, len;
char str[16];
freopen("e:\\test\\in.txt", "r", stdin);
scanf("%d%d", &n, &m);
for (i = 0; i < m*2; i += 2) {
scanf("%d%d%d%s", &a, &b, &len, str);
add_edge(i, a, b, len);
add_edge(i+1, b, a, len);
}
scanf("%d", &k);
for (i = 0; i < k*2; i += 2) {
scanf("%d%d", &a, &b);
add_query(i, a, b);
add_query(i+1, b, a);
}
dfs(1, 0);
for (i = 0; i < k*2; i += 2)
printf("%d\n", max(queries[i].ans, queries[i+1].ans));
return 0;
}
#define MAX_N 40032
#define MAX_Q 10032
struct edge_node {
struct edge_node *next;
int idx, len;
} ;
struct edge_node edges[MAX_N * 2 ];
struct tree_node {
struct edge_node *edge;
struct query_node *query;
int depth, visited;
} ;
struct tree_node tree[MAX_N];
struct query_node {
int idx, ans;
struct query_node *next;
} ;
struct query_node queries[MAX_Q * 2 ];
struct set_node {
int parent, len;
} ;
struct set_node set [MAX_N];
__inline int max( int a, int b)
{
return a > b ? a : b;
}
__inline int find( int idx)
{
static int stack[MAX_N];
int i, sp;
for (sp = 0; set[idx].parent; sp++) {
stack[sp] = idx;
idx = set[idx].parent;
}
for (sp--; sp >= 0; sp--) {
i = stack[sp];
set[i].len += set[set[i].parent].len;
set[i].parent = idx;
}
return idx;
}
__inline void add_edge( int idx, int a, int b, int len)
{
struct edge_node *p = &edges[idx];
p->idx = b;
p->len = len;
p->next = tree[a].edge;
tree[a].edge = p;
}
__inline void add_query( int idx, int a, int b)
{
struct query_node *p = &queries[idx];
p->idx = b;
p->next = tree[a].query;
tree[a].query = p;
}
void dfs( int idx, int depth)
{
struct edge_node *e;
struct query_node *q;
int i;
tree[idx].visited = 1;
tree[idx].depth = depth;
for (q = tree[idx].query; q; q = q->next) {
if (!tree[q->idx].visited)
continue;
i = find(q->idx);
q->ans = tree[q->idx].depth + depth - 2*tree[i].depth;
}
for (e = tree[idx].edge; e; e = e->next) {
if (tree[e->idx].visited)
continue;
dfs(e->idx, depth + e->len);
set[e->idx].parent = idx;
set[e->idx].len = e->len;
}
}
int main()
{
int n, m, k, i, a, b, len;
char str[16];
freopen("e:\\test\\in.txt", "r", stdin);
scanf("%d%d", &n, &m);
for (i = 0; i < m*2; i += 2) {
scanf("%d%d%d%s", &a, &b, &len, str);
add_edge(i, a, b, len);
add_edge(i+1, b, a, len);
}
scanf("%d", &k);
for (i = 0; i < k*2; i += 2) {
scanf("%d%d", &a, &b);
add_query(i, a, b);
add_query(i+1, b, a);
}
dfs(1, 0);
for (i = 0; i < k*2; i += 2)
printf("%d\n", max(queries[i].ans, queries[i+1].ans));
return 0;
}
DFS+RMQ:
#include
<
stdio.h
>
#define MAX_N 40032
int rmq[MAX_N * 2 ][ 16 ], seq[MAX_N * 2 ], seq_cnt, map[MAX_N];
struct edge_node {
struct edge_node *next;
int idx, len;
} ;
struct edge_node edges[MAX_N * 2 ];
struct tree_node {
struct edge_node *edge;
int depth, visited;
} ;
struct tree_node tree[MAX_N];
__inline int min( int a, int b)
{
return a < b ? a : b;
}
__inline void add_edge( int idx, int a, int b, int len)
{
struct edge_node *p = &edges[idx];
p->idx = b;
p->len = len;
p->next = tree[a].edge;
tree[a].edge = p;
}
__inline void add_seq( int idx)
{
seq[seq_cnt] = idx;
if (!map[idx])
map[idx] = seq_cnt;
seq_cnt++;
}
void dfs( int idx, int depth)
{
struct edge_node *e;
tree[idx].visited = 1;
tree[idx].depth = depth;
for (e = tree[idx].edge; e; e = e->next) {
if (tree[e->idx].visited)
continue;
add_seq(idx);
add_seq(e->idx);
dfs(e->idx, depth + e->len);
}
}
__inline void rmq_init()
{
int i, len, j;
for (i = 1; i < seq_cnt; i++)
rmq[i][0] = tree[seq[i]].depth;
for (i = 1; ; i++) {
len = 1 << i;
if (1 + len > seq_cnt)
break;
for (j = 1; j + len <= seq_cnt; j++)
rmq[j][i] = min(rmq[j][i - 1], rmq[j + len/2][i - 1]);
}
}
__inline int rmq_query( int start, int end)
{
int len, i;
len = end - start + 1;
for (i = 0; (1 << i) <= len; i++);
i--;
return min(rmq[start][i], rmq[end + 1 - (1 << i)][i]);
}
int main()
{
int n, m, i, j, a, b, len;
char str[16];
freopen("e:\\test\\in.txt", "r", stdin);
scanf("%d%d", &n, &m);
for (i = 0; i < m*2; i += 2) {
scanf("%d%d%d%s", &a, &b, &len, str);
add_edge(i, a, b, len);
add_edge(i+1, b, a, len);
}
seq_cnt = 1;
dfs(1, 0);
rmq_init();
scanf("%d", &i);
while (i--) {
scanf("%d%d", &a, &b);
if (map[a] > map[b]) {
j = a;
a = b;
b = j;
}
j = rmq_query(map[a], map[b]);
printf("%d\n", tree[a].depth + tree[b].depth - 2*j);
}
return 0;
}
#define MAX_N 40032
int rmq[MAX_N * 2 ][ 16 ], seq[MAX_N * 2 ], seq_cnt, map[MAX_N];
struct edge_node {
struct edge_node *next;
int idx, len;
} ;
struct edge_node edges[MAX_N * 2 ];
struct tree_node {
struct edge_node *edge;
int depth, visited;
} ;
struct tree_node tree[MAX_N];
__inline int min( int a, int b)
{
return a < b ? a : b;
}
__inline void add_edge( int idx, int a, int b, int len)
{
struct edge_node *p = &edges[idx];
p->idx = b;
p->len = len;
p->next = tree[a].edge;
tree[a].edge = p;
}
__inline void add_seq( int idx)
{
seq[seq_cnt] = idx;
if (!map[idx])
map[idx] = seq_cnt;
seq_cnt++;
}
void dfs( int idx, int depth)
{
struct edge_node *e;
tree[idx].visited = 1;
tree[idx].depth = depth;
for (e = tree[idx].edge; e; e = e->next) {
if (tree[e->idx].visited)
continue;
add_seq(idx);
add_seq(e->idx);
dfs(e->idx, depth + e->len);
}
}
__inline void rmq_init()
{
int i, len, j;
for (i = 1; i < seq_cnt; i++)
rmq[i][0] = tree[seq[i]].depth;
for (i = 1; ; i++) {
len = 1 << i;
if (1 + len > seq_cnt)
break;
for (j = 1; j + len <= seq_cnt; j++)
rmq[j][i] = min(rmq[j][i - 1], rmq[j + len/2][i - 1]);
}
}
__inline int rmq_query( int start, int end)
{
int len, i;
len = end - start + 1;
for (i = 0; (1 << i) <= len; i++);
i--;
return min(rmq[start][i], rmq[end + 1 - (1 << i)][i]);
}
int main()
{
int n, m, i, j, a, b, len;
char str[16];
freopen("e:\\test\\in.txt", "r", stdin);
scanf("%d%d", &n, &m);
for (i = 0; i < m*2; i += 2) {
scanf("%d%d%d%s", &a, &b, &len, str);
add_edge(i, a, b, len);
add_edge(i+1, b, a, len);
}
seq_cnt = 1;
dfs(1, 0);
rmq_init();
scanf("%d", &i);
while (i--) {
scanf("%d%d", &a, &b);
if (map[a] > map[b]) {
j = a;
a = b;
b = j;
}
j = rmq_query(map[a], map[b]);
printf("%d\n", tree[a].depth + tree[b].depth - 2*j);
}
return 0;
}