http://poj.org/problem?id=3694
08年的合肥赛区网络赛,这里求u,v的LCA只是常数时间复杂度
#define N 100010
struct edge{
int v;
int next;
}e[N*10];
int ecnt;
int head[N];
void init(){
ecnt = 0;
memset(head,-1,sizeof(head));
}
void add(int u,int v){
e[ecnt].v = v;
e[ecnt].next = head[u];
head[u] = ecnt++;
e[ecnt].v = u;
e[ecnt].next = head[v];
head[v] = ecnt++;
}
int low[N],dfn[N];
int fa[N];
bool cut[N];
int n,m;
int t;
int ans;
//tarjan求无向图双连通图
void tarjan(int u){
low[u] = dfn[u] = ++t;
int i;
for(i=head[u];i!=-1;i=e[i].next){
int v = e[i].v;
if(v == fa[u])continue;
if(!dfn[v]){
fa[v] = u;
tarjan(v);
low[u] = min(low[u],low[v]);
if(dfn[u]<low[v]){//v点最早的祖先不能得到它的父结点时,v就是割点
cut[v] = 1;
ans++;
}
} else low[u] = min(low[u],dfn[v]);//回溯时更新low[u],其中u是与割点v相邻且属于同一分量的点
}
}
void LCA(int x,int y){//朴素LCA公共祖先,利用dfn的记录一直往上爬直到公共祖先
while(dfn[x]<dfn[y]){
if(cut[y]){
cut[y] = 0;
ans--;
}
y = fa[y];
}
while(dfn[x]>dfn[y]){
if(cut[x]){
cut[x] = 0;
ans--;
}
x = fa[x];
}
while(x!=y){
if(cut[x]){
cut[x] = 0;
ans--;
}
if(cut[y]){
cut[y] = 0;
ans--;
}
x = fa[x];
y = fa[y];
}
}
int main(){
int ca=1;
while(scanf("%d%d",&n,&m) && (n+m)){
int i,j;
init();
while(m--){
int a,b;
scanf("%d%d",&a,&b);
add(a,b);
}
t = ans = 0;
memset(dfn,0,sizeof(dfn));
memset(cut,0,sizeof(cut));
tarjan(1);
scanf("%d",&m);
printf("Case %d:\n",ca++);
while(m--){
int a,b;
scanf("%d%d",&a,&b);
LCA(a,b);
printf("%d\n",ans);
}
puts("");
}
return 0;
}
话说hdu有一模一样的题目,但总是RE栈溢出,可能数据有问题。。。