AIM Tech R3 div2 E Centroid

思路很明顯了,假設是點x,則看它的子樹中是否有大於n/2的,若是有,則在該子樹中剪去它能夠剪的且小於n/2的,接到點x上。ios

 

則統計出在以x點爲根的子樹中,它的各子樹能夠剪去的且小於n/2的最大子子樹。對於除去以x爲根的子樹的其餘部分,記爲up,則一樣地統計它的能夠剪除的符合條件的子樹,最後對每一個點判斷一下就能夠了。spa

代碼以下::(額,想的時候對up的這個不知道怎麼寫~謝指導)blog

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
//#include <bitset>
using namespace std;

const int MAXN = 400010;

vector<int> t[MAXN];
int par[MAXN], sz[MAXN], up[MAXN], dw[MAXN], n;

void dfs_sz(int u, int parent){
	par[u] = parent;
	sz[u] = 1;
	int size = t[u].size();
	for(int i = 0; i< size; i++){
		int v = t[u][i];
		if(v == parent) continue;
		dfs_sz(v, u);
		sz[u] += sz[v];
	}
}

void dfs_down(int u, int parent){
	dw[u] = (sz[u] <= n/2 ? sz[u] : 0);
	int size = t[u].size();	
	for(int i = 0; i < size; i++){
		int v = t[u][i];
		if(v == parent) continue;
		dfs_down(v, u);
		dw[u] = max(dw[u], dw[v]);
	}
}

void dfs_up(int u, int parent, int val){
	up[u] = max((n - sz[u] <= n /2? n - sz[u]: 0), val);
	int size = t[u].size();
	
	int mx0 = 0, mx1 = 0;
	
	for(int i = 0; i < size; i++){
		int v = t[u][i];
		if(v == parent) continue;
		if(dw[v] >= mx0){
			mx1 = mx0;
			mx0 = dw[v];
		}
		else if(dw[v] >= mx1){
			mx1 = dw[v];
		}	
	}
	
	for(int i = 0; i < size ; i++){
		int v = t[u][i];
		if(v == parent) continue;
		dfs_up(v, u, max(up[u], (mx0 == dw[v]? mx1 : mx0 )));
		
	}
	
	
}



int main(){
	
	int u, v;
	
	scanf("%d", &n);
	for(int i = 1; i< n; i++){
		scanf("%d%d", &u, &v);
		t[u].push_back(v);
		t[v].push_back(u);
	}
	
	dfs_sz(1, -1);
	dfs_down(1, -1);
	dfs_up(1, -1, 0);
	
	for(int i = 1; i <= n; i++){
		int ans = 1;
		int size = t[i].size();
		for(int k = 0; k < size; k++){
			int u = t[i][k];
			if(u == par[i]){
				if(n - sz[i] - up[i] > n/2)
					ans = 0;
			}
			else {
				if(sz[u] - dw[u] > n/ 2)
					ans = 0;
			}
			
		}
		printf("%d", ans);
		if(i == n) printf("\n");
		else printf(" ");
		
	}
	
	
	
	
	return 0;
}
相關文章
相關標籤/搜索