题面我就不写了
做这道题花了我一个多小时
天知道我经历了什么???
ok今天上午刚讲的tarjan综合
这道题就类似于模板题了
先tarjan无向图双连通分量缩点
然后重新建个图
这个图已经变成了一棵树
在这棵树上dfs一遍找出深度
然后用tarjan做离线lca
具体怎么做呢
简单来说就是
结合并查集思想
在遍历这个点的所有去点后更新fa
然后找到和它有关的(也就是要求的lca的另外一个点)点
如果此点被处理过
lca就是find(这个点)
为什么对自己脑补一下
然后你要求的这两点之间的点数是
depth[x]+depth[y]-2*depth[lca]+1
然后贴代码:
(可能会比较乱因为调了好几次)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#define N 10005
#define M 50005
using namespace std;
int n,m,q,cnt,head[N],bel[N],dcc,cnt2,head2[N];
int dfn[N],low[N],fa[N],num,stk[N],top;
int a[M],b[M],ans[M],depth[N];
bool vis[N],used[N];
vector<int> dc[M];
struct EDGE{
int to,nxt;
}edge[M*2];//原图
struct EDGE2{
int to,nxt,frm;
}e[M*2];//新图
inline int rd(){
int x=0,f=1; char c=' ';
while(c>'9' || c<'0') {if(c=='-') f=-1;c=getchar();}
while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
return x*f;
}
inline void add(int x,int y){
cnt++;
edge[cnt].to=y;
edge[cnt].nxt=head[x];
head[x]=cnt;
}
void add2(int x,int y){
cnt2++;
e[cnt2].nxt=head2[x];
e[cnt2].to=y;
e[cnt2].frm=x;
head2[x]=cnt2;
}
void tarjan(int x,int father){
dfn[x]=low[x]=++num;
stk[++top]=x;
vis[x]=1;
for(int i=head[x];i;i=edge[i].nxt){
int y=edge[i].to;
if(y==father) continue;
if(!dfn[y]){
tarjan(y,x);
low[x]=min(low[y],low[x]);
}
else if(vis[y]) low[x]=min(low[x],dfn[y]);
}
if(dfn[x]==low[x]){
++dcc;
int tmp;
do{
tmp=stk[top--];
vis[tmp]=0;//注意这里
bel[tmp]=dcc;
dc[dcc].push_back(tmp);
}while(tmp!=x);
}
}//缩点
void rebuild(){
for(int i=1;i<=dcc;i++){
for(int j=0;j<dc[i].size();j++){
int u=dc[i][j];
for(int k=head[u];k;k=edge[k].nxt){
int v=edge[k].to;
if(bel[v]!=bel[u]) add2(bel[u],bel[v]);//注意这里的if条件
}
}
}
}
void dfs(int x,int dep){
depth[x]=dep;
for(int i=head2[x];i;i=e[i].nxt){
int y=e[i].to;
if(!depth[y]) dfs(y,dep+1);
}
return;
}
int find(int x){
if(fa[x]==x) return x;
return fa[x]=find(fa[x]);
}
void LCA(int x){
fa[x]=x;
used[x]=1;//我不会说因为used写错位置调了我20分钟
for(int i=head2[x];i;i=e[i].nxt){
int y=e[i].to;
if(used[y]) continue;
LCA(y);
fa[y]=x;//在处理后更新fa
}
for(int i=1;i<=q;i++){
if(ans[i]) continue;
if(bel[a[i]]==x){//这两行就是遍历所有去点后处理lca
if(used[bel[b[i]]]) ans[i]=depth[bel[a[i]]]+depth[bel[b[i]]]-2*depth[find(bel[b[i]])]+1;
}//因为各种没加depth或者没加bel wa了好几遍
if(bel[b[i]]==x){
if(used[bel[a[i]]]) ans[i]=depth[bel[a[i]]]+depth[bel[b[i]]]-2*depth[find(bel[a[i]])]+1;
}
}
return ;
}
int main(){
n=rd(); m=rd();
for(int i=1;i<=m;i++){
int x,y;
x=rd(); y=rd();
add(x,y); add(y,x);
}
q=rd();
for(int i=1;i<=q;i++){
a[i]=rd(); b[i]=rd();
}
tarjan(1,0);
rebuild();
dfs(1,1);
LCA(1);
for(int i=1;i<=q;i++){
int x=ans[i];
if(x<0) {printf("0\n");continue;}
int c[64],cn=0;//二进制处理
while(x>0){
if(x&1) c[++cn]=1;
else c[++cn]=0;
x/=2;
}
for(int j=cn;j>=1;j--) printf("%d",c[j]);
printf("\n");
}
return 0;
}
这道题写的真是令人憔悴