题意:
给一张图,求有多少个无序点对
(x,y)
(
x
,
y
)
满足
存在一条
存
在
一
条
1
到
到
x1
到
到
y1$这一个公共点。
题解:
支配树
求出必经点之后就是支配树上lca为1的点对数量了。
#include<bits/stdc++.h>
using namespace std;
inline int rd(){
char ch=getchar();int i=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=getchar();}
return i*f;
}
const int N=1e5+50,M=1e6+50;
int n,m;
long long ans;
int dfn[N],id[N],fa[N],sze[N],ind;
int anc[N],mnsd[N],sdom[N],idom[N];
vector<int>pre[N];
vector<int>buc[N];
struct Graph*tr;
struct Graph{
int g[N],nt[M],v[M],ec;
inline void adde(int x,int y){
nt[++ec]=g[x];g[x]=ec;v[ec]=y;
}
inline void dfs(int x){
sze[x]=1;
for(int e=g[x];e;e=nt[e]){
dfs(v[e]);
if(x==1)ans+=1ll*sze[x]*sze[v[e]];
sze[x]+=sze[v[e]];
}
}
inline void add(int x,int y){
nt[++ec]=g[x];g[x]=ec;v[ec]=y;
pre[y].push_back(x);
}
inline void getanc(int p){
if(anc[p]!=p)getanc(anc[p]);
if(dfn[sdom[mnsd[anc[p]]]]<dfn[sdom[mnsd[p]]])
mnsd[p]=mnsd[anc[p]];
anc[p]=anc[anc[p]];
}
inline int eval(int p){
getanc(p);
return mnsd[p];
}
inline void dfs(int x,int f){
dfn[x]=++ind;id[ind]=x;fa[x]=f;
mnsd[x]=(anc[x]=(sdom[x]=x));
for(int e=g[x];e;e=nt[e]){
if(dfn[v[e]])continue;
dfs(v[e],x);
}
}
inline void build(){
for(int i=ind;i>=2;i--){
int u=id[i];
for(int p=pre[u].size()-1;p>=0;p--){
int x=pre[u][p],t=eval(x);
if(dfn[sdom[t]]<dfn[sdom[u]])sdom[u]=sdom[t];
}
int f=fa[u];
anc[u]=f;
buc[sdom[u]].push_back(u);
for(int p=buc[f].size()-1;p>=0;p--){
int x=buc[f][p],t=eval(x);
if(dfn[sdom[x]]>dfn[sdom[t]])idom[x]=t;
else idom[x]=sdom[x];
}
buc[f].clear();
}
for(int i=2;i<=ind;i++){
int u=id[i];
if(idom[u]!=sdom[u])idom[u]=idom[idom[u]];
tr->adde(idom[u],u);
}
}
}ori,g;
int main(){
tr=&g;
n=rd(),m=rd();
for(int i=1;i<=m;i++){
int x=rd(),y=rd();
ori.add(x,y);
}
ori.dfs(1,1);
ori.build();
tr->dfs(1);
cout<<ans<<endl;
}