将树形结构转化成线性结构,那么我们就可以将问题转化为求一个区间内,恰好出现K次的权值有多少种。我们记录树状数组第k位表示k到i的答案,假设v出现的位置是在p1; p2; p3; ; pk,那么我们假设现在枚举到了pk这个位置,将pk这个位置的数字加入集合之后,p(k−K−1) + 1到p(k−K)这部分区间内权值v出现次数就超过K了,p(k−K )+ 1到p(k−K+1)这部分区间内权值v出现的次数恰好达到K,所以我们将树状数组中的p(k−K−1) + 1到p(k−K)内的值全部减1,p(k−K) +1到p(k−K+1)内的值全部加1。查询的时候是查询左端点前数的和。
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
using namespace std;
const int MAXN = 100010;
const int MAXQ = 100010;
int add[MAXN<<2];
struct Edge {
int u, v, next;
Edge() {}
Edge(int t_u, int t_v) : u(t_u), v(t_v) {}
}edges[2*MAXN];
int head[MAXN], edge_sum;
int T, N, K, Q;
int L[MAXN], R[MAXN];
int W[MAXN], A[MAXN];
bool visit[MAXN];
int id;
map<int,int> myMap;
vector<int> vec[MAXN];
int ans[MAXN];
void init() {
edge_sum = 0;
memset(head, -1, sizeof(head));
memset(visit, false, sizeof(visit));
}
void addEdge(int u, int v) {
edges[edge_sum].u = u;
edges[edge_sum].v = v;
edges[edge_sum].next = head[u];
head[u] = edge_sum++;
edges[edge_sum].u = v;
edges[edge_sum].v = u;
edges[edge_sum].next = head[v];
head[v] = edge_sum++;
}
void dfs(int u) {
visit[u] = true;
L[u] = ++id;
A[id] = W[u];
for(int i = head[u]; i != -1; i = edges[i].next) {
int v = edges[i].v;
if(!visit[v]) {
dfs(v);
}
}
R[u] = id;
return ;
}
void pushdown(int rt) {
if(add[rt]) {
add[rt<<1] += add[rt];
add[rt<<1|1] += add[rt];
add[rt] = 0;
}
return ;
}
void bulid(int l, int r, int rt) {
add[rt] = 0;
if(l == r) return ;
int m = (l + r)>>1;
bulid(l, m, rt<<1);
bulid(m + 1, r, rt<<1|1);
return ;
}
void update(int l, int r, int rt, int L, int R, int c) {
if(L == l && R == r) {
add[rt] += c;
return ;
}
pushdown(rt);
int m = (l + r)>>1;
if(R <= m) {
update(l, m, rt<<1, L, R, c);
} else if(L > m) {
update(m + 1, r, rt<<1|1, L, R, c);
} else {
update(l, m, rt<<1, L, m, c);
update(m + 1, r, rt<<1|1, m + 1, R, c);
}
return ;
}
int query(int l, int r, int rt, int pos) {
if(l == r) {
return add[rt];
}
pushdown(rt);
int m = (l + r)>>1;
if(pos <= m) return query(l, m, rt<<1, pos);
else return query(m + 1, r, rt<<1|1, pos);
}
struct Query {
int l, r, id;
Query() {}
Query(int t_l, int t_r, int t_id) : l(t_l), r(t_r), id(t_id) {}
friend bool operator < (const Query &q1, const Query &q2) {
if(q1.r == q2.r) {
return q1.l < q2.l;
}
return q1.r < q2.r;
}
}QQ[MAXQ];
int main() {
//freopen("aa.in", "r", stdin);
int u, v;
scanf("%d", &T);
for(int kcase = 1; kcase <= T; ++kcase) {
if(kcase > 1) puts("");
scanf("%d %d", &N, &K);
init(); myMap.clear(); id = 0;
for(int i = 0; i <= N; ++i) {
vec[i].clear();
}
for(int i = 1; i <= N; ++i) {
scanf("%d", &W[i]);
if(myMap.count(W[i]) == 0) {
myMap[W[i]] = ++id;
}
W[i] = myMap[W[i]];
}
for(int i = 1; i < N; ++i) {
scanf("%d %d", &u, &v);
addEdge(u, v);
}
id = 0; dfs(1);
scanf("%d", &Q);
for(int i = 1; i <= Q; ++i) {
scanf("%d", &u);
QQ[i].l = L[u];
QQ[i].r = R[u];
QQ[i].id = i;
}
sort(QQ + 1, QQ + Q + 1); id = 1;
bulid(1, N, 1);
for(int i = 1; i <= N; ++i) {
int val = A[i];
vec[val].push_back(i);
int size = vec[val].size();
if(size >= K) {
if(size == K) {
update(1, N, 1, 1, vec[val][size-K], 1);
} else {
if(size - K - 2 >= 0) {
update(1, N, 1, vec[val][size-K-2]+1, vec[val][size-K-1], -1);
} else {
update(1, N, 1, 1, vec[val][size-K-1], -1);
}
update(1, N, 1, vec[val][size-K-1]+1, vec[val][size-K], 1);
}
}
while(QQ[id].r == i) {
ans[QQ[id].id] = query(1, N, 1, QQ[id].l);
id++;
}
}
printf("Case #%d:\n", kcase);
for(int i = 1; i <= N; ++i) {
printf("%d\n", ans[i]);
}
}
return 0;
}