제출 #1196960

#제출 시각아이디문제언어결과실행 시간메모리
1196960nouka28철인 이종 경기 (APIO18_duathlon)C++20
31 / 100
212 ms92892 KiB
#include<bits/stdc++.h>
using namespace std;

// #include<atcoder/all>
// using namespace atcoder;
// using mint=atcoder::modint998244353;

#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")

#define int long long

#define rep(i,n) for(int i=0;i<(n);i++)
#define rng(i,l,r) for(int i=(l);i<(r);i++)
#define rrep(i,n) for(int i=(n)-1;i>=0;i--)
#define rrng(i,l,r) for(int i=(r)-1;i>=(l);i--)

#define fi first
#define se second
#define all(x) (x).begin(),(x).end()

struct fast_io{fast_io(){std::cin.tie(nullptr)->sync_with_stdio(false);}}_;

struct LowLink{
	vector<vector<int>> g;
	int n;
	vector<int> ord,low;
	vector<vector<int>> son,back_edge;
	vector<int> tps;

	LowLink(vector<vector<int>> g_){
		g=g_,n=(int)g.size();
		ord.assign(n,-1);low.assign(n,-1);
		son.assign(n,vector<int>());back_edge.assign(n,vector<int>());
		tps.clear();
		int t=0;
		stack<pair<int,int>> st;
		vector<bool> conduct(n,false);
		for(int i=0;i<n;i++){
			if(conduct[i])continue;
			st.push({-1,i});
			while(!st.empty()){
				auto[pre,now]=st.top();st.pop();
				conduct[now]=true;
				if(ord[now]!=-1){
					if(ord[pre]<ord[now])continue;
					low[pre]=min(low[pre],ord[now]);
					back_edge[pre].push_back(now);
					continue;
				}
				if(pre!=-1){
					son[pre].push_back(now);
				}
				tps.push_back(now);
				ord[now]=low[now]=t;t++;
				for(int nex:g[now]){
					if(nex==pre)continue;
					st.push({now,nex});
				}
			}
		}
		for(int i=(int)tps.size()-1;i>=0;i--){
			for(int e:son[tps[i]]){
				low[tps[i]]=min(low[tps[i]],low[e]);
			}
		}
	}
	
	vector<pair<int,int>> bridges(){
		vector<pair<int,int>> res;
		for(int i=0;i<n;i++){
			for(int e:son[i]){
				if(low[e]>ord[i]){
					res.push_back({min(i,e),max(i,e)});
				}
			}
		}
		return res;
	}

	//tecc,tecc_idx,tecc_tree
	tuple<vector<vector<int>>,vector<int>,vector<vector<int>>> TwoEdgeConnectedComponentDecomposition(){
		vector<vector<int>> tecc,tecc_tree;
		vector<int> tecc_idx(n,-1);
		stack<pair<int,int>> sub_roots;
		int idx=0;
		vector<bool> conduct(n,false);
		for(int i=0;i<n;i++){
			if(conduct[i])continue;
			sub_roots.push({-1,i});
			while(!sub_roots.empty()){
				stack<pair<int,int>> st;st.push(sub_roots.top());sub_roots.pop();
				tecc.push_back(vector<int>());tecc_tree.push_back(vector<int>());
				while(!st.empty()){
					auto[pre,now]=st.top();st.pop();
					conduct[now]=true;
					tecc[idx].push_back(now);
					tecc_idx[now]=idx;
					if(pre!=-1&&idx!=tecc_idx[pre]){
						tecc_tree[idx].push_back(tecc_idx[pre]);
						tecc_tree[tecc_idx[pre]].push_back(idx);
					}
					for(auto e:son[now]){
						if(low[e]>ord[now]){
							sub_roots.push({now,e});
						}else{
							st.push({now,e});
						}
					}
				}
				idx++;
			}
		}
		return {tecc,tecc_idx,tecc_tree};
	}

	//bce,bcv,is_ap
	tuple<vector<vector<pair<int,int>>>,vector<vector<int>>,vector<bool>> BiconnectedComponentDecomposition(){
		vector<vector<pair<int,int>>> bce;
		vector<vector<int>> bcv;
		vector<bool> is_ap(n,false);
		stack<pair<int,int>> sub_roots;
		vector<bool> conduct(n,false);
		int idx=0;
		for(int i=0;i<n;i++){
			if(conduct[i])continue;
			sub_roots.push({-1,i});
			while(!sub_roots.empty()){
				stack<pair<int,int>> st;st.push(sub_roots.top());sub_roots.pop();
				bce.push_back(vector<pair<int,int>>());bcv.push_back(vector<int>());
				if(st.top().first!=-1){
					bcv[idx].push_back(st.top().first);
				}
				while(!st.empty()){
					auto[pre,now]=st.top();st.pop();
					conduct[now]=true;
					if(pre!=-1)bce[idx].push_back({pre,now});
					bcv[idx].push_back(now);
					if(now==i){
						if((int)son[now].size()>1){
							for(int e:son[now]){
								is_ap[now]=true;
								sub_roots.push({now,e});
							}
							bce.pop_back();bcv.pop_back();idx--;
						}else{
							for(int e:son[now]){
								st.push({now,e});
							}
						}
					}else{
						for(int e:son[now]){
							if(low[e]>=ord[now]){
								is_ap[now]=true;
								sub_roots.push({now,e});
							}else{
								st.push({now,e});
							}
						}
					}
					if(now==i&&(int)son[now].size()<=1){
						for(int back:back_edge[now]){
							bce[idx].push_back({now,back});
						}
					}
				}
				idx++;
			}
		}
		return {bce,bcv,is_ap};
	}

	//bc,bc_idx,bc_tree,num_ap,bce,bcv,is_ap
	struct block_cut_tree_result{
		vector<vector<int>> bc;
		vector<int> bc_idx;
		vector<vector<int>> bc_tree;
		int num_ap;
		vector<vector<pair<int,int>>> bce;
		vector<vector<int>> bcv;
		vector<bool> is_ap;
	};
	
	block_cut_tree_result block_cut_tree(){
		auto[bce,bcv,is_ap]=BiconnectedComponentDecomposition();
		int num_ap=0;for(bool f:is_ap)num_ap+=f;
		vector<vector<int>> bc(num_ap+(int)bcv.size(),vector<int>());
		vector<int> bc_idx(n,-1);
		vector<vector<int>> bc_tree(num_ap+(int)bcv.size(),vector<int>());
		int idx=0;
		for(int i=0;i<n;i++){
			if(is_ap[i]){
				bc[idx].push_back(i);
				bc_idx[i]=idx;
				idx++;
			}
		}
		for(vector<int> bcv_i:bcv){
			for(int v:bcv_i){
				if(is_ap[v]){
					bc_tree[idx].push_back(bc_idx[v]);
					bc_tree[bc_idx[v]].push_back(idx);
				}else{
					bc[idx].push_back(v);
					bc_idx[v]=idx;
				}
			}
			idx++;
		}
		return {bc,bc_idx,bc_tree,num_ap,bce,bcv,is_ap};
	}
	
};


signed main(){
	int N,M;cin>>N>>M;
	vector<vector<int>> g(N);
	rep(i,M){
		int u,v;cin>>u>>v;u--;v--;
		g[u].push_back(v);
		g[v].push_back(u);
	}

	LowLink lowlink(g);

	auto ret=lowlink.block_cut_tree();
	int ans=0;

	vector<bool> flg(ret.bc_tree.size());
	rep(i,flg.size()){
		if(flg[i])continue;
		auto q=[&](auto q,int p,int prev=-1)->int {
			flg[p]=1;
			int now=ret.bc[p].size();
			for(auto&&e:ret.bc_tree[p]){
				if(e==prev)continue;
				now+=q(q,e,p);
			}
			return now;
		};
		int n=q(q,i);

		auto dfs=[&](auto dfs,int p,int prev=-1)->int {
			int nsz=ret.bc[p].size();
			int sz_sum=nsz;
			if(p<ret.num_ap){
				int tmp=(n-1)*(n-2);
				for(auto&&e:ret.bc_tree[p]){
					if(e==prev)continue;
					int t=dfs(dfs,e,p);
					sz_sum+=t;
					int t2=t-ret.bc[e].size();
					tmp-=t2*(t2-1);
				}
				if(prev!=-1){
					int t2=(n-sz_sum-ret.bc[prev].size());
					tmp-=t2*(t2-1);
				}
				ans+=tmp;
			}else{
				int tmp=(n-1)*(n-2);
				for(auto&&e:ret.bc_tree[p]){
					if(e==prev)continue;
					int t=dfs(dfs,e,p);
					sz_sum+=t;
					tmp-=t*(t-1);
				}
				if(prev!=-1){
					int t=(n-sz_sum);
					tmp-=t*(t-1);
				}
				ans+=nsz*tmp;
			}

			return sz_sum;
		};

		dfs(dfs,i);
	}
	cout<<ans<<endl;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...