题目大意:给一棵树,1为根。每个节点都有一个权值。Q次询问,每个询问为,以x为根的子树中,刚好出现了k次的权有几种。
关键是要把树形结构边为线性结构,我们这里使用欧拉序列,问题变为了一个区间,刚好出现了k次的数字有几个。
这个问题则是很经典的离线问题了,线段树点i的值表示区间[i,j]中,刚好出现了k次的数字的个数(j具有动态意义)。我们用id[x][j]表示,数字x在整个数列中第j次出现的位置。每次维护的时候就是区间 idx[x][j-k]+1 到 id[x][j-k+1] 全部+1,区间 id[x][j-k-1]+1 到 id[x][j-k] 全部-1。
#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<cctype>
#include<string>
#include<algorithm>
#include<iostream>
#include<ctime>
#include<map>
#include<set>
using namespace std;
#define MP(x,y) make_pair((x),(y))
#define PB(x) push_back(x)
typedef __int64 LL;
//typedef unsigned __int64 ULL;
/* ****************** */
const int INF=1000111222;
const double INFF=1e200;
const double eps=1e-8;
const int mod=1000000007;
const int NN=100010;
const int MM=10010;
/* ****************** */
const int MOD=233341;
int hash[MOD];
vector<int>id[MOD];
int a[NN],b[NN],ll[NN],rr[NN],tsp;
struct G
{
int v,next;
}E[NN*2];
int p[NN],T;
struct Q
{
int l,r,id,ans;
bool operator<(const Q& tt)const
{
return r<tt.r;
}
}line[NN];
int lazy[NN*4];
void add(int u,int v)
{
E[T].v=v;
E[T].next=p[u];
p[u]=T++;
}
int get_hash(int x)
{
int key=x%MOD;
for(;;key++)
{
if(key==MOD)
key=0;
if(hash[key]==-1 || hash[key]==x)
{
hash[key]=x;
return key;
}
}
return -1;
}
void dfs(int u,int fa)
{
ll[u]=++tsp;
int i,v;
for(i=p[u];i+1;i=E[i].next)
{
v=E[i].v;
if(v==fa)
continue;
dfs(v,u);
}
rr[u]=tsp;
}
void push_down(int R)
{
if(lazy[R]!=0)
{
lazy[R<<1]+=lazy[R];
lazy[R<<1|1]+=lazy[R];
lazy[R]=0;
}
}
int get_mid(int l,int r)
{
return (l+r)>>1;
}
void update(int l,int r,int R,int st,int en,int ad)
{
if(l<=st && en<=r)
{
lazy[R]+=ad;
return;
}
push_down(R);
int mid=get_mid(st,en);
if(l<=mid)
update(l,r,R<<1,st,mid,ad);
if(r>mid)
update(l,r,R<<1|1,mid+1,en,ad);
}
int query(int x,int R,int st,int en)
{
if(st==en)
return lazy[R];
push_down(R);
int mid=get_mid(st,en);
if(x<=mid)
return query(x,R<<1,st,mid);
return query(x,R<<1|1,mid+1,en);
}
bool cmp(Q x,Q y)
{
return x.id<y.id;
}
void solve(int n,int q,int k)
{
memset(lazy,0,sizeof(lazy));
int i,x,ge,j=1;
for(i=1;i<=n;i++)
{
x=a[i];
id[x].push_back(i);
ge=id[x].size()-1;
if(ge>=k)
{
update(id[x][ge-k]+1,id[x][ge-k+1],1,1,n,1);
if(ge-k>0)
{
update(id[x][ge-k-1]+1,id[x][ge-k],1,1,n,-1);
}
}
while(j<=q && line[j].r==i)
{
line[j].ans=query(line[j].l,1,1,n);
j++;
}
}
sort(line+1,line+1+q,cmp);
for(i=1;i<=q;i++)
{
printf("%d\n",line[i].ans);
}
}
int main()
{
int cas,ee=0;
int n,k;
int i,x,y,q;
scanf("%d",&cas);
while(cas--)
{
memset(hash,-1,sizeof(hash));
memset(p,-1,sizeof(p));
T=0;
tsp=0;
for(i=0;i<MOD;i++)
{
id[i].clear();
id[i].push_back(0);
}
scanf("%d%d",&n,&k);
for(i=0;i<n;i++)
{
scanf("%d",&a[i]);
b[i+1]=get_hash(a[i]);
}
// for(i=1;i<=n;i++)
// printf("%d%c",b[i],i==n?'\n':' ');
for(i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dfs(1,-1);
for(i=1;i<=n;i++)
{
a[ll[i]]=b[i];
}
/*
for(i=1;i<=n;i++)
{
printf("%d %d\n",ll[i],rr[i]);
printf("w==%d\n",a[i]);
}
*/
scanf("%d",&q);
for(i=1;i<=q;i++)
{
scanf("%d",&x);
line[i].l=ll[x];
line[i].r=rr[x];
line[i].id=i;
}
sort(line+1,line+1+q);
printf("Case #%d:\n",++ee);
solve(n,q,k);
if(cas)
puts("");
}
return 0;
}