tarjan,找环
比赛时先看错了题,然后,想出来方案再到编码没赶上。
coding还是太慢了。要刻意练习。
关键信息在于n个节点n条边。
我们注意到了,这其实就是一棵树再加上一条边。
树中形成了一个环。
我们把这个环单独拿出来,将其他节点视作有这个环上的节点向外的延申。
也就是以这个环的每一个节点为根生成了一个又一个的树。
我们可以统计每个树的简单路径,然后再统计经过了这个环后的简单路径。
如何统计经过了这个环后的简单路径呢?
我们注意到经过这个环,那么这条路径的两个端点一定是在不同的树中,而因为是环
所以对于同样的起点终点我们有两条不同的路径。
故,算法完毕。
但是,麻烦的事来了。
我们如何找到这个环呢?
利用类似tajian的做法,一边dfs一边染色,同时人工模仿一个栈。
代码如下:
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int max_n = 2e5+100;
typedef long long ll;
struct edge{
int to,next;
}E[max_n<<1];
int head[max_n];
int cnt=1;
void add(int from,int to){
E[cnt].to=to;E[cnt].next=head[from];
head[from] = cnt++;
}
vector<int> v,stack;
bool f = true;
bool vis[max_n];
void dfs(int u,int fa){
vis[u]=true;
stack.push_back(u);
for (int i=head[u];i;i=E[i].next){
int vv = E[i].to;
if (vv==fa)continue;
else if (vis[vv]){
while (stack.back()!=vv){
v.push_back(stack.back());
stack.pop_back();
}v.push_back(vv);
f = false;
return;
}
else{
dfs(vv,u);
if (!f)return;
else stack.pop_back();
}
}
}
bool used[max_n];
ll cct[max_n];
ll Dfs(int u,int fa){
ll ans =1;
for (int i=head[u];i;i=E[i].next){
int v = E[i].to;
if (v==fa||used[v])continue;
ll tmp=Dfs(v,u);
ans+=Dfs(v,u);
}return cct[u]=ans;
}
ll ddfs(int u,int fa){
vector<ll> tmp;
ll ans = 0;ll sum=0;
for (int i=head[u];i;i=E[i].next){
int v = E[i].to;
if (v==fa||used[v])continue;
tmp.push_back(cct[v]);
ans+=ddfs(v,u);
ans+=cct[v];
sum+=cct[v];
}
ll ttt = 0;
for (int num:tmp)ttt+=num*(sum-num);
ttt>>=1;
ans+=ttt;
return ans;
}
ll ans = 0;
int n;
int main(){
int t;scanf("%d",&t);
while (t--){
f=true;ans = 0;
stack.clear(),v.clear();
int n;scanf("%d",&n);
fill(head,head+n+10,0);cnt=1;
fill(vis,vis+n+10,0);
fill(used,used+n+10,0);
fill(cct,cct+n+10,0);
for (int i=1,u,v;i<=n;++i){
scanf("%d %d",&u,&v);
add(u,v);add(v,u);
}
dfs(1,0);
for (int aa:v)used[aa]=true;
vector<ll> res;ll sum = 0;
for (int i=0;i<v.size();++i){
Dfs(v[i],0);sum+=cct[v[i]];
res.push_back(cct[v[i]]);
}
for (int i=0;i<v.size();++i){
ans+=ddfs(v[i],0);
}
for (int i=0;i<res.size();++i){
ans+=res[i]*(sum-res[i]);
}
printf("%lld\n",ans);
}
}
京公网安备 11010502036488号