题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=4358
2012年多校,6场,1009。
方法: 离散化 + 树状数组 + 离线处理
电科牛出的风骚题目,膜拜膜拜。。。
理解了N久。。。 树状数组用到了区间更新,单点询问。。。
问区间内,有多少个出现了K次的数,这个用树状数组去做。。。 具体上电科牛的题解。。。
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn = 100010;
int N,K,cnt,Q;
int s[maxn],si[maxn];
struct Edge{
int v,nxt;
}eg[maxn];
int tol,reg[maxn];
void add_edge(int u,int v){
eg[tol].v=v;
eg[tol].nxt=reg[u];
reg[u]=tol++;
}
int L[maxn],R[maxn],NN,rec[maxn];
void dfs(int v){
L[v]=++NN;
rec[NN]=v;
for(int i=reg[v];i!=-1;i=eg[i].nxt)
dfs(eg[i].v);
R[v]=NN;
}
int tree[maxn];
void add(int v,int val){
while(v>0){
tree[v]+=val;
v-=v&-v;
}
}
int query(int v){
int sum=0;
while(v<=NN){
sum+=tree[v];
v+=v&-v;
}
return sum;
}
vector<int> vec[maxn];
void add_queue(int v,int val){
vec[val].push_back(v);
int t=vec[val].size();
if(t==K){
add(vec[val][t-K],1);
}
else if(t>K){
add(vec[val][t-K],1);
add(vec[val][t-K-1],-2);
}
}
struct Query{
int i,l,r;
}qry[maxn];
int res[maxn];
int cmpqry(const Query &a,const Query &b){
return a.r<b.r;
}
void deal(){
sort(qry,qry+Q,cmpqry);
int i,j=0;
for(i=1;i<=NN;i++){
add_queue(i,s[rec[i]]);
while(j<Q && qry[j].r==i){
res[qry[j].i]=query(qry[j].l);
j++;
}
}
}
int cmp(int a,int b){
return s[a]<s[b];
}
void init_(){
sort(si+1,si+1+N,cmp);
for(int i=1;i<=cnt;i++)
vec[i].clear();
cnt=0;
for(int tmp=-1,i=1;i<=N;i++)
if(s[si[i]]!=tmp) tmp=s[si[i]],s[si[i]]=++cnt;
else s[si[i]]=cnt;
}
int main(){
int t,tt=1,tmp;
scanf("%d",&t);
while(t--){
scanf("%d%d",&N,&K);
for(int i=1;i<=N;i++){
scanf("%d",&s[i]);
si[i]=i;
reg[i]=-1;
tree[i]=0;
}
init_();
int u,v;
tol=0;
while(--N){
scanf("%d%d",&u,&v);
add_edge(u,v);
}
NN=0;
dfs(1);
scanf("%d",&Q);
for(int i=0;i<Q;i++){
scanf("%d",&tmp);
qry[i].i=i;
qry[i].l=L[tmp];
qry[i].r=R[tmp];
}
deal();
printf("Case #%d:\n",tt++);
for(int i=0;i<Q;i++)
printf("%d\n",res[i]);
if(t) puts("");
}
return 0;
}