http://poj.org/problem?id=3694
08年的合肥賽區網路賽,這裡求u,v的LCA只是常數時間複雜度
#define N 100010struct 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棧溢出,可能資料有問題。。。