CF600E Lomsat gelral

CF600E Lomsat gelral

題目大意

很清楚吧

題解

這是 dsu on tree(中文是啥??)入門題QWQ

首先考慮暴力,很簡單

考慮有技巧的暴力

先輕重鏈剖分

當到樹上的一個節點的時候,

先把輕兒子暴力算一遍,把貢獻刪了

然後再把重兒子算一遍, 不用刪貢獻,

再把輕兒子的貢獻加到重兒子上面就可以了

時間複雜度爲什麼是對的呢???

對於每個節點,他只可能被它祖先的輕邊遍歷到,而一個節點到根最多隻會經過log條輕邊,所以當前節點最多隻會被遍歷log次

爲什麼一個節點到根最多隻會經過log條輕邊
考慮對於每個點,它的輕兒子的大小一定小於其他所有兒子的大小的和,所以節點的數量會除以二

同樣,如果當前節點是作爲輕兒子,那它往上跳的時候節點數量爲至少乘2

所以做多經過log條輕邊

然後代碼實現就很簡單了

#include<bits/stdc++.h>
#define N 100005
using namespace std;
struct edge {
	int v, nxt;
}e[N << 1];
int p[N], eid;
void init() {
	memset(p, -1, sizeof p);
	eid = 0;
}
void insert(int u, int v) {
	e[eid].v = v;
	e[eid].nxt = p[u];
	p[u] = eid ++;
}
int size[N], w[N], cnt[N], col[N], n;
long long MC, CC, ans[N];
void dfs1(int u, int fa) {
	size[u] = 1;
	for(int i = p[u]; i + 1; i = e[i].nxt) {
		int v = e[i].v;
		if(v == fa) continue;
		dfs1(v, u);
		if(size[v] > size[w[u]]) w[u] = v;
		size[u] += size[v];
	}
}
void calc(int u, int fa, int o, int W) {
	cnt[col[u]] += o;
	if(cnt[col[u]] == MC) CC += col[u];
	if(cnt[col[u]] > MC) MC = cnt[col[u]], CC = col[u];
	
	for(int i = p[u]; i + 1; i = e[i].nxt) {
		int v = e[i].v;
		if(v == fa || v == W) continue;
		calc(v, u, o, W);			
	}
}
void dfs2(int u, int fa, int o) {
	for(int i = p[u]; i + 1; i = e[i].nxt) {
		int v = e[i].v;
		if(v == fa || v == w[u]) continue;
		dfs2(v, u, -1);
	}
	if(w[u]) dfs2(w[u], u, 1);
	calc(u, fa, 1, w[u]);
	ans[u] = CC;
	if(o == -1) {
		calc(u, fa, -1, 0);
		MC = 0, CC = 0;
	}
}
int main() {
	init();
	scanf("%d", &n);
	for(int i = 1; i <= n; i ++) scanf("%d", &col[i]);
	for(int i = 1; i < n; i ++) {
		int u, v;
		scanf("%d%d", &u, &v);
		insert(u, v);
		insert(v, u);
	}
	dfs1(1, 0);
	dfs2(1, 0, 1);
	for(int i = 1; i <= n; i ++) printf("%lld ", ans[i]);
	return 0;
}

坑點

long long


感覺沒有啓發式合併 or 線段樹合併好寫啊 QWQ

發佈了156 篇原創文章 · 獲贊 86 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章