题目大意:
给定一个无向图,求满足从s能够到c,从c能够到f,且两条路路径不经过重复点的三元组(s,c,f)的个数。
思路:
考虑怎么计算这种三元组,可以枚举s和f,然后计算从s到f的点不重复路径中可以经过的点的个数。
s到t点不重复路径中可以经过的点必定在也只能在这条路径所经过的点双内。所以可以考虑缩点双之后建出圆方树,然后就只需要在树上求出每一对(u,v)之间经过的点双点数大小。
直接将点双大小加起来的话两个点双的公共点会算重,于是将公共点的权值(圆点)设为-1,方点的权值设为点双的大小。两边的点也不能要,于是答案便转化成了求树上所有的圆点对之间的路径权值和。
直接做是
n2
n
2
,可以计算每一个点的贡献,复杂度线性。
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;++i)
typedef long long ll;
using namespace std;
void File(){
freopen("loj2587.in","r",stdin);
freopen("loj2587.out","w",stdout);
}
template<typename T>void read(T &_){
T __=0,mul=1; char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')mul=-1;
ch=getchar();
}
while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
_=__*mul;
}
const int maxn=1e5+10;
const int maxm=2e5+10;
int n,m;
int beg[maxn],las[maxm<<1],to[maxm<<1],cnte=1;
int dfn[maxn],low[maxn],cnt_dfn,tot;
vector<int>G[maxn<<1];
stack<int>stk;
ll sz[maxn<<1],ans,val[maxn<<1];
bool vis[maxn<<1];
void add(int u,int v){
las[++cnte]=beg[u]; beg[u]=cnte; to[cnte]=v;
las[++cnte]=beg[v]; beg[v]=cnte; to[cnte]=u;
}
void tarjan(int u,int f){
stk.push(u);
low[u]=dfn[u]=++cnt_dfn;
for(int i=beg[u];i;i=las[i]){
if(to[i]==f)continue;
if(!dfn[to[i]]){
tarjan(to[i],u);
low[u]=min(low[u],low[to[i]]);
if(low[to[i]]>=dfn[u]){
++tot; int cnt=0;
for(int p=0;p!=to[i];stk.pop(),++cnt){
p=stk.top(); val[p]=-1;
G[tot].push_back(p);
G[p].push_back(tot);
}
val[u]=-1;
G[tot].push_back(u);
G[u].push_back(tot);
val[tot]=cnt+1;
}
}
else low[u]=min(low[u],dfn[to[i]]);
}
}
void init(){
read(n); read(m); tot=n;
int u,v;
REP(i,1,m)read(u),read(v),add(u,v);
REP(i,1,n)if(!dfn[i])tarjan(i,0);
}
void get_sz(int u,int f){
vis[u]=1;
if(u<=n)sz[u]=1;
for(int siz=G[u].size()-1,i=0;i<=siz;++i){
if(G[u][i]==f)continue;
get_sz(G[u][i],u);
sz[u]+=sz[G[u][i]];
}
}
void dfs(int u,int f,int rt){
for(int siz=G[u].size()-1,i=0;i<=siz;++i){
if(G[u][i]==f)continue;
dfs(G[u][i],u,rt);
ans+=val[u]*sz[G[u][i]]*(sz[rt]-sz[G[u][i]]-(u<=n));
//cout<<u<<" "<<val[u]<<" "<<sz[G[u][i]]<<" "<<(sz[rt]-sz[G[u][i]]-(u<=n))<<endl;
}
ans+=val[u]*(sz[u]-(u<=n))*(sz[rt]-sz[u]);
//cout<<val[u]<<"fuck"<<(sz[u]-(u<=n))<<" "<<(sz[rt]-sz[u])<<endl;
}
void work(){
REP(i,1,tot)if(!vis[i]){
get_sz(i,0);
dfs(i,0,i);
ans-=sz[i]*(sz[i]-1)*2;
}
}
int main(){
File();
init();
work();
printf("%lld\n",ans);
return 0;
}