各种模板。。。
边双联通分量+LCA
#include<cstring>
#include<cstdio>
#include<stack>
#include<algorithm>
#define mod 1000000007
#define N 100100
using namespace std;
typedef long long ll;
int head1[N],head2[N],head3[N],cnt;
int scc,depth,dfn[N],low[N],belong[N];
int ok[N],sum[N];
stack<int>sta;
struct Edge{
int v,next;
}edge[N*4];
int f[N],flag[N];
ll ans[N];
struct Query{
int v,id,next;
}query[N*2];
void addedge(int u,int v,int *head){
edge[cnt].v=v;
edge[cnt].next=head[u];
head[u]=cnt++;
edge[cnt].v=u;
edge[cnt].next=head[v];
head[v]=cnt++;
}
void addedge1(int u,int v,int id){
query[cnt].v=v;
query[cnt].id=id;
query[cnt].next=head3[u];
head3[u]=cnt++;
query[cnt].v=u;
query[cnt].id=id;
query[cnt].next=head3[v];
head3[v]=cnt++;
}
void init(){
memset(head1,-1,sizeof(head1));
memset(head2,-1,sizeof(head2));
memset(head3,-1,sizeof(head3));
memset(dfn,0,sizeof(dfn));
memset(ok,0,sizeof(ok));
memset(sum,0,sizeof(sum));
memset(f,0,sizeof(f));
memset(flag,0,sizeof(flag));
cnt=depth=scc=0;
}
void tarjan(int u,int fa){
int i;
dfn[u]=low[u]=++depth;
sta.push(u);
for(i=head1[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
if(v==fa)continue;
if(dfn[v]==0){
tarjan(v,u);
low[u]=min(low[u],low[v]);
}
else
low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u]){
scc++;
int cou=0;
while(1){
int tem=sta.top();
sta.pop();
belong[tem]=scc;
cou++;
if(tem==u)break;
}
if(cou>1)ok[scc]=1;
}
}
void dfs(int u,int fa){
int i;
sum[u]=sum[fa]+ok[u];
for(i=head2[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
if(v==fa)continue;
dfs(v,u);
}
}
int find(int u){
if(f[u]==u)return u;
return f[u]=find(f[u]);
}
ll quick(int num){
ll summ=1,zi=2;
while(num){
if(num%2)
summ=(summ*zi)%mod;
zi=(zi*zi)%mod;
num/=2;
}
return summ;
}
void Tarjan(int u,int fa){
int i;
f[u]=u;
for(i=head2[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
if(v!=fa){
Tarjan(v,u);
f[v]=u;
}
}
flag[u]=1;
for(i=head3[u];i!=-1;i=query[i].next){
int v=query[i].v;
if(flag[v]){
int t=find(v);
ans[query[i].id]=quick(sum[u]+sum[v]-2*sum[t]+ok[t]);
}
}
}
int main(){
int k,i,n,m;
int u,v;
scanf("%d %d",&n,&m);
init();
for(i=1;i<=m;i++){
scanf("%d %d",&u,&v);
addedge(u,v,head1);
}
for(i=1;i<=n;i++)
if(!dfn[i])
tarjan(i,0);
int last=cnt; //这里注意一下
for(i=0;i<last;i+=2) //建新图
if(belong[edge[i].v]!=belong[edge[i+1].v])
addedge(belong[edge[i].v],belong[edge[i+1].v],head2);
dfs(1,0);
scanf("%d",&k);
cnt=0; //这里注意一下
for(i=1;i<=k;i++){
scanf("%d %d",&u,&v);
addedge1(belong[u],belong[v],i);
}
Tarjan(1,0);
for(i=1;i<=k;i++)
printf("%I64d\n",ans[i]);
}
本文提供了一个结合边双联通分量和最近公共祖先(LCA)算法的C++实现模板,用于解决图论中涉及连通性和层次结构的问题。该模板通过构建边双联通分量来优化LCA的查询过程,并使用并查集进行路径压缩,适用于竞赛编程等场景。
277

被折叠的 条评论
为什么被折叠?



