长链剖分

编程学习

Posted by simplex on March 22, 2021

长链剖分

将一棵树根据重儿子分为若干条极长链,然后将重儿子的状态直接转移到他的父亲

CF1009F模板

// author: M@
#define m_
//#define _DEBUG_
#include<iostream>
//#include<cstdio>
//#include<string.h>
//#include<iomanip>
//#include<queue>
//#include<vector>
//#include<map>
//#include<algorithm>
//#include<cmath>
//#include<list>
//#include<set>
//#include<string>
#define clr(a)   memset((a),0,sizeof (a))
#define li idx<<1
#define ri idx<<1|1

using namespace std;
typedef unsigned int ui;
typedef long long LL;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f;
const LL LINF=1e18;
const double DINF=1e9;
const double EPS=1e-9;

const int maxn=1e6+5;
const int maxm = 3005;
int n;
struct edg{
	int to, nxt;
}e[maxn * 2];
int son[maxn];
int *dp[maxn];
int ans[maxn];
int  dep[maxn], ms[maxn];//³¤Á´ÆÊ·Ö 
int cnt;

void add_edg(int x, int fx){
	e[++cnt].to = x;
	e[cnt].nxt = son[fx];
	son[fx] = cnt;
}


int dfs0(int idx, int fa){
		int mdep = 0;
		ms[idx] = idx;
		for(int i = son[idx]; i != 0; i = e[i].nxt){
			int to = e[i].to;
			if(to == fa){
				continue;
			}
			int dd = dfs0(to, idx);
			if(mdep < dd){
				ms[idx] = to;
				mdep = dd;
			}
		}
		return mdep + 1;
}

int dfs(int idx, int fa, int td){
//	printf("%d\n", idx);
//	ans[idx] = 0;
	if(ms[idx] == idx){
		dp[idx] = new int [td + 1];
		dp[idx][td] = 1;
		ans[idx] = 0;
		return 1;
	}
	int to = ms[idx];
	int dd = dfs(to, idx, td + 1);
	int ld = dd + 1;
	dp[idx] = dp[to];
	dp[idx][td] = 1;
	ans[idx] = ans[to] + 1;
	int mdd = 0;
	for(int i = son[idx]; i != 0; i = e[i].nxt){
		int to = e[i].to;
		if(fa == to || ms[idx] == to){
			continue;
		}
		int dd = dfs(to, idx, 0);
		mdd = max(mdd, dd);
		for(int j = 1; j <= dd; j++){
			dp[idx][td + j] += dp[to][j - 1];
		}
		delete dp[to];
	}
	for(int i = 0; i <= mdd; i++){
		if(dp[idx][td + i] > dp[idx][ans[idx] + td] || dp[idx][td + i] == dp[idx][ans[idx] + td] && i < ans[idx]){
			ans[idx] = i;
		}
//		printf("dp[%d][%d] = %d   ",  idx, td+i, dp[idx][td+i]);
	}
	return ld;
//	printf("idx: %d   ", idx);
//	for(int i = 0; i <= m; i++){
//		printf("%d " , dp[idx][i]);
//	}puts("");
}



int main()
{
#ifdef m_
    freopen("input.txt","r",stdin);
//    freopen("output.txt","w",stdout);
#endif
	scanf("%d", &n);

	cnt = 0;
	
	for(int i = 1; i < n; i++){
		int x, fx;
		scanf("%d%d", &x, &fx);
		add_edg(x ,fx);
		add_edg(fx, x);
	}
	
	dfs0(1, 1);
	dfs(1, 1, 0);
//	for(int i = 1; i <= n; i++){
//		printf("%d  ", sNum[i]);
//	}puts("");
//	printf("%d\n", dp[midx]);
	for(int i = 1; i <= n; i++){
		printf("%d\n", ans[i]);
//		printf("ms: %d\n", ms[i]);
	}
	
#ifdef m_
    fclose(stdin);
//    fclose(stdout);
#endif
    return 0;
}