先考虑部分分...
( m Subtask 1 & 2):直接 (mathcal{O(n^4)}) 暴力做即可。
期望得分 ( m 16 pts)
( m Subtask 4 & 5):非环的情况,可以考虑树形 dp 去做。
设 (f_i) 为以 (i) 为中转点的点对数量,然后式子很显然...直接看代码如下:
for(int i=0;i<g[x].size();++i){
int v=g[x][i];
if(v==fath) continue;
dfs(v,x);
ans+=1ll*sz[x]*sz[v];
sz[x]+=sz[v];
}
++sz[x];
ans+=1ll*(all-sz[x])*(sz[x]-1);
由于图并不保证联通,所以用 all
来表示联通块的点的数量。
顺便一提由于 (s ightarrow c ightarrow f) 和 (f ightarrow c ightarrow s) 算两种不同的方案,所以最后答案还要乘个 (2)
期望得分 ( m 16+23=39 pts)
( m Subtask 6 & 7):仙人掌的情况...仙人掌+dp 那不就是在圆方树上 dp 吗...
跟上面一样设 (f_i) 为以 (i) 为中转点的点对数量,圆点的情况和原来差不多。
对于方点的情况...分类讨论一下。
设 (Bsz) 为方点代表的环的大小。
(s) 和 (f) 都在方点代表的环内:显然中转点有 (Bsz-2) 个
(s) 和 (f) 两个都不在方点代表的环内:有 (Bsz) 个中转点。然而会被 (2) 个圆点给计算过一次,发现会有重复,去重一下就有 (Bsz-2) 个中转点。
(s) 和 (f) 有且只有一个在方点代表的环内:(Bsz-1) 个中转点。发现会算重,去重一下 (Bsz-2) 个中转点。
综上所述中转点数量有 (Bsz-2) 个。于是在算的时候乘上一个 (Bsz-2) 的系数就行。
期望得分 ( m39+35=74 pts)
至于正解...直接对原图建广义圆方树,然后做法同 ( m Subtask 6 & 7) 。
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N=200000+5;
struct edge{
int nxt,to;
}e[N<<1];
int head[N],cnt=1;
vector<int> g[N];
void add(int x,int y){
e[++cnt].to=y; e[cnt].nxt=head[x]; head[x]=cnt;
}
int n,all,dfn[N],low[N],tot,sz[N],Bsz[N],amt;
stack<int> S;
void tarjan(int x,int fath){
dfn[x]=low[x]=++tot;
S.push(x);
++all;
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=fath){
int v=e[i].to;
if(!dfn[v]){
tarjan(v,x);
if(low[v]==dfn[x]){
++amt;
g[amt].push_back(x);
g[x].push_back(amt);
Bsz[amt]=1;
while(1){
int now=S.top();S.pop();
g[now].push_back(amt);
g[amt].push_back(now);
Bsz[amt]++;
if(now==v) break;
}
}
else if(low[v]>dfn[x]) S.pop(),g[x].push_back(v),g[v].push_back(x);
low[x]=min(low[x],low[v]);
}
else low[x]=min(low[x],dfn[v]);
}
}
long long ans;
void dfs(int x,int fath){
for(int i=0;i<g[x].size();++i){
int v=g[x][i];
if(v==fath) continue;
dfs(v,x);
if(x<=n) ans+=1ll*sz[x]*sz[v];
else ans+=1ll*(Bsz[x]-2)*sz[x]*sz[v];
sz[x]+=sz[v];
}
if(x<=n){
++sz[x];
ans+=1ll*(all-sz[x])*(sz[x]-1);
}
else ans+=1ll*(Bsz[x]-2)*(all-sz[x])*sz[x];
}
int main(){
int m;
cin>>n>>m;
int U,V;
for(int i=1;i<=m;++i){
cin>>U>>V;
add(U,V);add(V,U);
}
amt=n;
for(int i=1;i<=n;++i)
if(!dfn[i]){
all=0;
tarjan(i,0);
dfs(i,0);
}
cout<<ans*2ll;
return 0;
}