【CF600E】Lomsat gelral
【CF600E】Lomsat gelral
题面
给你一颗\(n\)个节点的树,每个节点都有一种颜色,\(m\)次询问,每次询问求每个子树中出现次数最多的颜色(们)的编号之和。
其中\(n\leq10^5,m\leq10^5\)
题解
\(dsu\;on\;tree\)板子题
不会的推荐看\(gsy\)的博客
其实还是挺简单的
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
inline int gi() {
register int data = 0, w = 1;
register char ch = 0;
while (ch != '-' && (ch > '9' || ch < '0')) ch = getchar();
if (ch == '-') w = -1 , ch = getchar();
while (ch >= '0' && ch <= '9') data = data * 10 + (ch ^ 48), ch = getchar();
return w * data;
}
#define MAX_N 100005
typedef long long ll;
struct Graph { int to, next; } e[MAX_N << 1];
int fir[MAX_N], e_cnt = 0;
void clearGraph() { memset(fir, -1, sizeof(fir)); e_cnt = 0; }
void Add_Edge(int u, int v) {
e[e_cnt].to = v, e[e_cnt].next = fir[u], fir[u] = e_cnt++;
}
int size[MAX_N], son[MAX_N];
ll ans[MAX_N], sum[MAX_N];
int num[MAX_N], top, c[MAX_N], N;
bool vis[MAX_N];
void dfs1(int x, int f) {
size[x] = 1;
for (int i = fir[x]; ~i; i = e[i].next) {
int v = e[i].to;
if (v == f) continue;
dfs1(v, x);
size[x] += size[v];
if (size[son[x]] < size[v]) son[x] = v;
}
}
void update(int x, int f, int opt) {
sum[num[c[x]]] -= c[x];
num[c[x]] += opt;
sum[num[c[x]]] += c[x];
if (sum[top + 1]) ++top;
if (!sum[top]) --top;
for (int i = fir[x]; ~i; i = e[i].next) {
int v = e[i].to;
if (v == f || vis[v]) continue;
update(v, x, opt);
}
}
void dfs2(int x, int f, bool hs) {
for (int i = fir[x]; ~i; i = e[i].next) {
int v = e[i].to;
if (v == f || v == son[x]) continue;
dfs2(v, x, 0);
}
if (son[x]) dfs2(son[x], x, 1), vis[son[x]] = 1;
update(x, f, 1); vis[son[x]] = 0;
ans[x] = sum[top];
if (!hs) update(x, f, -1);
}
int main() {
clearGraph();
N = gi();
for (int i = 1; i <= N; i++) c[i] = gi();
for (int i = 1; i < N; i++) {
int u = gi(), v = gi();
Add_Edge(u, v); Add_Edge(v, u);
}
dfs1(1, 0);
dfs2(1, 0, 1);
for (int i = 1; i <= N; i++) printf("%I64d ", ans[i]);
printf("\n");
return 0;
}