题目链接:
http://poj.org/problem?id=1470
题意:
给定若干有向边,构成有根数,给定若干查询,求每个查询的结点的LCA出现次数。
分析:
还是很裸的tarjan的LCA。
这题我真的要吐槽!!调试了好久啊!!不是MLE就是RE。。。。
- 查询数量没给,所以要用矩阵来存,这样还可以避免重复。
- 给边的时候不知道会不会有重复的点,所以讲道理应该用vector保存。
- getchar。。。我不知道为什么会RE。。。
- 其实ance数组可以不用的,只要每次处理子树的时候pa[v] = u即可。
代码:
#include<cstdio>
#include<cstring>
#include<vector>
#include<iostream>
using namespace std;
#define mem(a, b) memset(a, b, sizeof(a))
#define fuck cout<<"fuck"<<endl;
const int maxn = 1100;
vector<int>G[maxn];
int pa[maxn];
bool vis[maxn];
bool in[maxn];
int ance[maxn];
int cnt[maxn];
int root, n, tot;
int query[maxn][maxn];
int _find(int x)
{
if(pa[x] != x) return pa[x] = _find(pa[x]);
return x;
}
void unite(int x, int y)
{
int rx = _find(x), ry = _find(y);
if(rx == ry) return;
pa[rx] = ry;
}
void init()
{
for(int i = 1; i <= n; i++){
G[i].clear();
pa[i] = i;
}
mem(ance, 0);
mem(vis, false);
mem(query, 0);mem(cnt, 0);
mem(in, false);
}
void LCA(int u)
{
ance[u] = u;
for(int i = 0; i < G[u].size(); i++){
int v = G[u][i];
LCA(v);
unite(u, v);
ance[_find(u)] = u;
}
vis[u] = true;
for(int i = 1; i <= n; i++){
if(vis[i] && query[u][i]) cnt[ance[_find(i)]] += query[u][i];
}
}
int main(void)
{
int u, v, k;
int Q;
while(~scanf("%d",&n)){
init();
for(int i = 0; i < n; i++){
scanf("%d:(%d)",&u,&k);
while(k--){
scanf("%d",&v);
in[v] = true;
G[u].push_back(v);
}
}
scanf("%d",&Q);
for(int i = 0; i < Q; i++){
scanf(" (%d %d)",&u,&v);
query[u][v]++;
query[v][u]++;
}
for(root = 1; root <= n; root++){
if(!in[root]) break;
}
LCA(root);
for(int i = 1; i <= n ; i++)
if(cnt[i]) printf("%d:%d\n",i, cnt[i]);
}
return 0;
}