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); } }