답안 #111472

# 제출 시각 아이디 문제 언어 결과 실행 시간 메모리
111472 2019-05-15T12:49:38 Z Pro_ktmr 철인 이종 경기 (APIO18_duathlon) C++14
0 / 100
346 ms 50800 KB
#include"bits/stdc++.h"
using namespace std;
#define LL long long
#define PB push_back
#define MP make_pair

//Union-Find木(サイズ有り)
struct UnionFind{
private:
	vector<int> parent;
	vector<int> size;
public:
	void init(int N){ //初期化する O(N)
		parent.clear();
		size.clear();
		for(int i=0; i<N; i++) parent.push_back(i);
		for(int i=0; i<N; i++) size.push_back(1);
	}
	int root(int a){ //親を返す O(log N)
		if(parent[a] == a) return a;
		return parent[a] = root(parent[a]);
	}
	void unite(int a, int b){ //木を併合する O(log N)
		int rootA = root(a);
		int rootB = root(b);
		if(rootA == rootB) return;
		if(size[rootA] < size[rootB]){
			parent[rootA] = rootB;
			size[rootB] += size[rootA];
			size[rootA] = 0;
		}
		else{
			parent[rootB] = rootA;
			size[rootA] += size[rootB];
			size[rootB] = 0;
		}
	}
	bool same(int a, int b){ //属する木が同じかを返す O(log N)
		return root(a) == root(b);
	}
	long long culcSize(int a){ //属する木の要素数を返す O(log N)
		return size[root(a)];
	}
	void decrement(int a, int x){
		a = root(a);
		size[a] -= x;
	}
};

LL N, M;
vector<int> edge[100000];
vector<bool> canUse[100000];
int sz[100000];

int pre[100000]={}, low[100000];
int c = 0;
vector<pair<int, int>> bridge;
UnionFind fact;
int dfs(int now, int par, int idx){
	if(pre[now] != 0) return pre[now];
	if(par != -1) fact.unite(now, par);
	pre[now] = c; c++;
	low[now] = pre[now];
	for(int i=0; i<edge[now].size(); i++){
		if(edge[now][i] == par) continue;
		low[now] = min(low[now], dfs(edge[now][i], now, i));
	}
	if(low[now] == pre[now] && par != -1){
		bridge.PB(MP(now, par));
		canUse[par][idx] = false;
		for(int i=0; i<edge[now].size(); i++)
			if(edge[now][i] == par) canUse[now][i] = false;
	}
	return low[now];
}

UnionFind uf;
bool flg[100000] ={};
void bfs(int now){
	if(flg[now]) return;
	queue<int> que;
	que.push(now);
	flg[now] = false;
	while(!que.empty()){
		int now = que.front();
		que.pop();
		for(int i=0; i<edge[now].size(); i++){
			if(!canUse[now][i]){

				continue;
			}
			if(flg[edge[now][i]]) continue;
			uf.unite(now, edge[now][i]);
			flg[edge[now][i]] = true;
			que.push(edge[now][i]);
		}
	}
}

vector<int> newEdge[100000];
int newSize[100000];
int newPar[100000] = {};
int newDfs(int now, int par){
	if(newPar[now] != 0) return newSize[now];
	newPar[now] = par;
	newSize[now] = uf.culcSize(now);
	sort(newEdge[now].begin(), newEdge[now].end());
	newEdge[now].erase(unique(newEdge[now].begin(), newEdge[now].end()), newEdge[now].end());
	for(int i=0; i<newEdge[now].size(); i++){
		if(newEdge[now][i] == par) continue;
		newSize[now] += newDfs(newEdge[now][i], now);
	}
	return newSize[now];
}

int main(){
	cin >> N >> M;
	for(int i=0; i<M; i++){
		int a, b;
		cin >> a >> b;
		edge[a-1].PB(b-1);
		canUse[a-1].PB(true);
		edge[b-1].PB(a-1);
		canUse[b-1].PB(true);
	}
	for(int i=0; i<N; i++) sz[i] = edge[i].size();

	//橋の検出
	for(int i=0; i<N; i++) low[i] = INT_MAX;
	fact.init(N);
	for(int i=0; i<N; i++) dfs(i,-1,-1);

	//二重辺連結成分分解(オリジナル実装)
	uf.init(N);
	for(int i=0; i<N; i++) bfs(0);
	for(int i=0; i<N; i++){
		for(int j=0; j<edge[i].size(); i++){
			if(!uf.same(i, edge[i][j])){
				newEdge[uf.root(i)].PB(uf.root(edge[i][j]));
				newEdge[uf.root(edge[i][j])].PB(uf.root(i));
			}
		}
	}

	/*
	//葉の検出
	queue<int> que;
	for(int i=0; i<N; i++){
		if(uf.root(i) != i) continue;
		if(newEdge[i].size() == 1) que.push(i);
	}
	*/

	//部分木の大きさ計算
	for(int i=0; i<N; i++){
		if(fact.root(i) != i) continue;
		newDfs(i, -1);
	}

	//答えの計算
	LL ans = 0;
	for(int i=0; i<N; i++){
		if(fact.root(i) == i){
			LL s = fact.culcSize(i);
			ans += s * (s-1) * (s-2);
		}
	}
	for(int i=0; i<N; i++){
		if(uf.root(i) != i) continue;
		int sum = 0;
		for(int j=0; j<newEdge[i].size(); j++){
			int now = newEdge[i][j];
			if(now == newPar[i]) continue;
			else{
				ans -= uf.culcSize(i) * newSize[now] * (newSize[now]-1);
				sum += newSize[now];
			}
		}
		sum = fact.culcSize(i) - sum - uf.culcSize(i);
		ans -= uf.culcSize(i) * sum * (sum-1);
	}
	
	cout << ans << endl;
}

Compilation message

count_triplets.cpp: In function 'int dfs(int, int, int)':
count_triplets.cpp:64:16: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
  for(int i=0; i<edge[now].size(); i++){
               ~^~~~~~~~~~~~~~~~~
count_triplets.cpp:71:17: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
   for(int i=0; i<edge[now].size(); i++)
                ~^~~~~~~~~~~~~~~~~
count_triplets.cpp: In function 'void bfs(int)':
count_triplets.cpp:87:17: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
   for(int i=0; i<edge[now].size(); i++){
                ~^~~~~~~~~~~~~~~~~
count_triplets.cpp: In function 'int newDfs(int, int)':
count_triplets.cpp:109:16: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
  for(int i=0; i<newEdge[now].size(); i++){
               ~^~~~~~~~~~~~~~~~~~~~
count_triplets.cpp: In function 'int main()':
count_triplets.cpp:137:17: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
   for(int j=0; j<edge[i].size(); i++){
                ~^~~~~~~~~~~~~~~
count_triplets.cpp:171:17: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
   for(int j=0; j<newEdge[i].size(); j++){
                ~^~~~~~~~~~~~~~~~~~
# 결과 실행 시간 메모리 Grader output
1 Correct 8 ms 8960 KB Output is correct
2 Correct 8 ms 8960 KB Output is correct
3 Correct 8 ms 8960 KB Output is correct
4 Correct 10 ms 8960 KB Output is correct
5 Correct 10 ms 8960 KB Output is correct
6 Correct 10 ms 8960 KB Output is correct
7 Incorrect 10 ms 8960 KB Output isn't correct
8 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Correct 8 ms 8960 KB Output is correct
2 Correct 8 ms 8960 KB Output is correct
3 Correct 8 ms 8960 KB Output is correct
4 Correct 10 ms 8960 KB Output is correct
5 Correct 10 ms 8960 KB Output is correct
6 Correct 10 ms 8960 KB Output is correct
7 Incorrect 10 ms 8960 KB Output isn't correct
8 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Correct 329 ms 29328 KB Output is correct
2 Correct 251 ms 29424 KB Output is correct
3 Runtime error 313 ms 50800 KB Execution killed with signal 11 (could be triggered by violating memory limits)
4 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Incorrect 12 ms 9088 KB Output isn't correct
2 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Runtime error 346 ms 43944 KB Execution killed with signal 11 (could be triggered by violating memory limits)
2 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Incorrect 14 ms 9088 KB Output isn't correct
2 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Runtime error 329 ms 43976 KB Execution killed with signal 11 (could be triggered by violating memory limits)
2 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Correct 8 ms 8960 KB Output is correct
2 Correct 8 ms 8960 KB Output is correct
3 Correct 8 ms 8960 KB Output is correct
4 Correct 10 ms 8960 KB Output is correct
5 Correct 10 ms 8960 KB Output is correct
6 Correct 10 ms 8960 KB Output is correct
7 Incorrect 10 ms 8960 KB Output isn't correct
8 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Correct 8 ms 8960 KB Output is correct
2 Correct 8 ms 8960 KB Output is correct
3 Correct 8 ms 8960 KB Output is correct
4 Correct 10 ms 8960 KB Output is correct
5 Correct 10 ms 8960 KB Output is correct
6 Correct 10 ms 8960 KB Output is correct
7 Incorrect 10 ms 8960 KB Output isn't correct
8 Halted 0 ms 0 KB -