tarjan可真是多才多艺,既求强连通,又求割点割边,还求lca,居然每一种都相差不多。
求割点主要是利用dfs遍历树(李顶龙童鞋一直不理解tarjan,从dfs树理解应该比较直观)。
rel[x]记录x实际在树中深度,low[x]记录x及其子树在树中回边可到达的最浅深度。
如果u是割点,那么在dfs树中
1、u为根,u有一个以上子树(删除u后显然两子树不连通)。
2、u非叶子(易知叶子无关紧要),且low[u的孩子]>=rel[u](即该子树无法不通过u到达u的祖先)
下面是代码(跑不到0ms)
附缩点双联通分量
每次点入栈,把回边和父亲边加进去
hdu3686
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
int tail[200000],next[2000000],sora[2000000],id[2000000],po[2000000];
int st[200000],f[50000][18],g[50000][18],rel[200000],low[200000],d[200000],flag[200000];
int top,n,m,ss,w_time,block,b[200000];
void link(int x,int y,int i)
{
++ss,next[tail[x]]=ss,tail[x]=ss,sora[ss]=y,next[ss]=0,id[ss]=i;
++ss,next[tail[y]]=ss,tail[y]=ss,sora[ss]=x,next[ss]=0,id[ss]=i;
po[ss]=ss-1,po[ss-1]=ss;
}
void link2(int x,int y)
{
// cout<<x<<' '<<y<<endl;
++ss,next[tail[x]]=ss,tail[x]=ss,sora[ss]=y,next[ss]=0;
++ss,next[tail[y]]=ss,tail[y]=ss,sora[ss]=x,next[ss]=0;
}
void dfs(int x,int y)
{
++w_time;
rel[x]=low[x]=w_time;
for (int i=x,ne;next[i];) {
i=next[i],ne=sora[i];
if (rel[ne]) st[++top]=id[i]+n;
}
st[++top]=x;
for (int i=x,ne;next[i];) {
i=next[i],ne=sora[i];
if (po[i]==y) continue;
if (rel[ne]) low[x]=min(low[x],rel[ne]);
else {
int tmp=top;
dfs(ne,i);
low[x]=min(low[x],low[ne]);
if (low[ne]>=rel[x]) {
flag[x]=flag[x+n+n]=1;
++block;
//cout<<x<<' '<<top<<' '<<tmp<<endl;
for (;top>tmp;top--) {
b[st[top]]=block;
// cout<<st[top]<<endl;
if (st[top]<=n && flag[st[top]]) {
link2(block,n+n+st[top]);
// cout<<st[top]<<' '<<block<<endl;
}
}
link2(block,n+n+x);
top=tmp;
}
}
}
}
void bfs(int s,int fl)
{
int h,r,ne,na;
h=r=0;
int k=(int)(log((double)n+n+n)/log(2.0))+1;
st[r=1]=s,rel[s]=fl,d[s]=0;
for (;h<r;) {
ne=st[++h];
for (int i=ne;next[i];) {
i=next[i],na=sora[i];
if (!rel[na]) {
rel[na]=fl,d[na]=d[ne]+1;
st[++r]=na;
f[na][0]=ne,g[na][0]=flag[na];
}
}
}
for (int j=1;j<=k;j++)
for (int i=1;i<=r;i++)
f[st[i]][j]=f[f[st[i]][j-1]][j-1],
g[st[i]][j]=g[st[i]][j-1]+g[f[st[i]][j-1]][j-1];
///cout<<r<<endl;
//for (int i=1;i<=r;i++) cout<<st[i]<<' '<<f[st[i]][0]<<endl;cout<<endl;
//cout<<f[7][0]<<endl;
}
int ask(int x,int y)
{
int e;
//cout<<x<<' '<<y<<endl;
if (d[x]<d[y]) e=x,x=y,y=e;
e=d[x]-d[y];
int ans=0;
for (int i=0;e;e>>=1,i++)
if (e&1) ans+=g[x][i],x=f[x][i];
//cout<<x<<' '<<y<<endl;
if (x==y) return ans+flag[x];
int k=0;
for (;;) {
if (f[x][k]==f[y][k]) {
if (!k) break;
k--;
}
else {
ans+=g[x][k]+g[y][k];
x=f[x][k],y=f[y][k];
}
}
ans+=g[x][k]+g[y][k];
x=f[x][k],y=f[y][k];
return ans+flag[x];
}
void origin()
{
ss=n+n+n;
for (int i=1;i<=n+n+n;i++) tail[i]=i,next[i]=0;
}
int l[200000],r[200000];
int main()
{
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
for (;;) {
scanf("%d%d",&n,&m);
if (!n && !m) break;
origin();
for (int i=1;i<=m;i++) {
int x,y;
scanf("%d%d",&x,&y);
l[i]=x,r[i]=y;
link(x,y,i);
}
for (int i=1;i<=n+n+n;i++) rel[i]=low[i]=flag[i]=d[i]=0;
for (int i=1;i<=n+m;i++) b[i]=0;
int k=(int)(log((double)n)/log(2.0))+1;
for (int i=1;i<=n+n+n;i++)
for (int j=0;j<=k;j++) f[i][j]=g[i][j]=0;
top=0,w_time=0,block=n;
for (int i=1;i<=n;i++)
if (!rel[i]) dfs(i,0);
//for (int i=1;i<=n+n+n;i++) cout<<flag[i]<<' ';cout<<endl;
//for (int i=1;i<=n+m;i++) cout<<b[i]<<' ';cout<<endl;
for (int i=n+1;i<=n+n;i++)
if (!rel[i]) bfs(i,i);
//for (int i=1;i<=n+n+n;i++) cout<<f[i][0]<<' ';cout<<endl;
int q;
scanf("%d",&q);
for (int i=1;i<=n;i++)
if (flag[i]) b[i]=i+n+n;
for (;q;q--) {
int x,y;
scanf("%d%d",&x,&y);
if ((b[x+n]==b[y+n]) || (rel[b[x+n]]!=rel[b[y+n]])) printf("0\n");
else {
int ans=ask(b[x+n],b[y+n]);
/* ans=min(ans,ask(b[l[x]],b[l[y]])-flag[l[x]]);
ans=min(ans,ask(b[r[x]],b[l[y]])-flag[r[x]]);
ans=min(ans,ask(b[l[x]],b[r[y]])-flag[l[x]]);
ans=min(ans,ask(b[r[x]],b[r[y]])-flag[r[x]]);*/
printf("%d\n",ans);
}
}
}
return 0;
}
拆边为点,考虑地更少
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
int ss,cnt,n,m,w_time,top,K,q;
int st[250000],rel[250000],low[250000],d[250000],tail[250000];
int b[250000],w[250000];
int f[250000][20],g[250000][20];
int next[2000000],sora[2000000];
vector <int> vec[250000];
void link(int x,int y)
{
++ss,next[tail[x]]=ss,tail[x]=ss,sora[ss]=y,next[ss]=0;
++ss,next[tail[y]]=ss,tail[y]=ss,sora[ss]=x,next[ss]=0;
}
void link2(int x,int y)
{
vec[x].push_back(y);
vec[y].push_back(x);
}
void dfs(int x,int y)
{
++w_time;
rel[x]=low[x]=w_time;
st[++top]=x;
for (int i=x,ne;next[i];) {
i=next[i],ne=sora[i];
if (ne==y) continue;
if (rel[ne]) low[x]=min(low[x],rel[ne]);
else {
int tmp=top;
dfs(ne,x);
low[x]=min(low[x],low[ne]);
if (low[ne]>=rel[x]) {
b[x]=x;
if (x<=n) w[x]=1;
b[++cnt]=cnt;
link2(x,cnt);
for (;top!=tmp;top--) {
int ne=st[top];
if (!b[ne]) b[ne]=cnt;
link2(ne,cnt);
}
}
}
}
}
void dfs2(int x,int s,int dis)
{
low[x]=s;
rel[x]=w_time;
d[x]=dis;
for (int i=0;i<vec[x].size();i++) {
int ne=vec[x][i];
if (rel[ne]!=w_time) {
f[ne][0]=x,g[ne][0]=w[x];
dfs2(ne,s,dis+1);
}
}
}
void origin()
{
ss=n+m;
for (int i=1;i<=n+m;i++) tail[i]=i,next[i]=0;
for (int i=1;i<=n+m;i++) rel[i]=low[i]=0;
w_time=0,top=0;
for (int i=1;i<=cnt;i++) vec[i].clear();
for (int i=1;i<=cnt;i++) w[i]=0,b[i]=0;
cnt=n+m;
}
int ask(int x,int y)
{
if (low[x]!=low[y]) return 0;
if (d[x]<d[y]) swap(x,y);
int e=d[x]-d[y];
int sum=0;
for (int b=0;e;e>>=1,b++)
if (e&1) sum+=g[x][b],x=f[x][b];
if (x==y) return sum;
for (int i=K;i>=0;i--)
if (f[x][i]!=f[y][i]) {
sum+=g[x][i]+g[y][i];
x=f[x][i],y=f[y][i];
}
if (x!=y) sum+=g[x][0];
return sum;
}
int main()
{
for (;scanf("%d%d",&n,&m)==2;) {
if (!n && !m) break;
origin();
for (int i=1;i<=m;i++) {
int x,y;
scanf("%d%d",&x,&y);
link(x,i+n);
link(i+n,y);
}
for (int i=1;i<=n+m;i++)
if (!rel[i]) dfs(i,0);
++w_time;
for (int i=1;i<=cnt;i++)
if (rel[i]!=w_time) f[i][0]=0,g[i][0]=0,dfs2(i,i,0);
K=(int)(log((double)cnt)/log(2.0))+1;
for (int j=1;j<=K;j++)
for (int i=1;i<=cnt;i++)
f[i][j]=f[f[i][j-1]][j-1],
g[i][j]=g[i][j-1]+g[f[i][j-1]][j-1];
scanf("%d",&q);
// cout<<cnt<<endl;
// cout<<f[7][0]<<' '<<f[8][0]<<' '<<f[6][0]<<endl;
for (int i=1;i<=q;i++) {
int x,y;
scanf("%d%d",&x,&y);
x+=n,y+=n;
int ans=ask(x,y);
printf("%d\n",ans);
}
}
return 0;
}