链接:http://acm.hdu.edu.cn/showproblem.php?pid=4358
给你一棵树,每个节点有一个点权,然后有一些询问,求以某个点为根的子树中有多少的数出现了k次
首先还是老方法,先转换成线性序列,每个节点对应一个区间,然后离线操作,每个询问都对应这一段区间,相当于询问一段区间内出现k次的数的个数,将所有询问的区间按照右端点排序,然后用线段树来做,线段树的第j个数代表[j,i]间出现k次的数的个数,记录下每个数出现的所有位置,当这个数出现k次的时候【1->这个数第1次出现的位置】这段区间内的数到i之间出现k次的数都多了一个,具体见代码
会爆栈,用到了模拟栈,vector删边不好删,于是也像朴素建邻接表那样开了一个head数组,记录下当前访问到了哪条边
#include<cstdio>
#include<vector>
#include<stack>
#include<algorithm>
using namespace std;
const int maxn = 100010;
typedef vector<int> VI;
int L[maxn],R[maxn];
VI edge[maxn];
int tot;
int val[maxn];
int num[maxn];
stack<int> s;
bool vis[maxn];
int head[maxn];
int n;
void dfs(int root){
while(!s.empty()) s.pop();
fill(vis,vis+n+1,false);
fill(head,head+n+1,0);
s.push(root);
while(!s.empty()) {
int now = s.top();
if(!vis[now]) {
L[now] = ++tot;
num[tot]=val[now];
vis[now] = true;
}
bool flag=false;
int sz=edge[now].size();
for(int i=head[now];i<sz;i++) {
int v=edge[now][i];
if(!vis[v]) {
flag = true;
s.push(v);
head[now]++;
break;
}
}
if(flag) continue;
if(vis[now]) {
R[now]=tot;
s.pop();
}
}
}
struct qq{
int v;
int l,r,id;
bool operator <(const qq& cmp)const{
return r < cmp.r;
}
}Q[maxn];
int add[maxn<<2];
void pushdown(int rt) {
if(add[rt]) {
add[rt<<1] += add[rt];
add[rt<<1|1] += add[rt];
add[rt] = 0;
}
}
void build(int l,int r,int rt){
add[rt]=0;
if(l==r) return ;
int m=l+r>>1;
build(l , m , rt<<1);
build(m+1 , r , rt<<1|1);
}
void update(int L,int R,int val,int l,int r,int rt){
if(L <= l && r <= R) {
add[rt]+=val;
return ;
}
pushdown(rt);
int m=l+r>>1;
if(L <= m) update(L,R,val,l,m,rt<<1);
if(R > m) update(L,R,val,m+1,r,rt<<1|1);
}
int query(int p,int l,int r,int rt){
if(l==r) return add[rt];
pushdown(rt);
int m=l+r>>1;
if(p <= m) return query(p,l,m,rt<<1);
return query(p,m+1,r,rt<<1|1);
}
int san[maxn];
VI pos[maxn];
int ans[maxn];
int main() {
int t,ca=0,k,u,v,q;
scanf("%d",&t);
while(t--) {
scanf("%d%d",&n,&k);
tot=0;
for(int i=1;i<=n;i++) scanf("%d",&val[i]),san[i]=val[i],edge[i].clear(),pos[i].clear();
for(int i=1;i<n;i++) {
scanf("%d%d",&u,&v);
edge[u].push_back(v);
edge[v].push_back(u);
}
sort(san+1,san+n+1);
int cnt=unique(san+1,san+n+1)-san-1;
for(int i=1;i<=n;i++) val[i]=lower_bound(san+1,san+cnt+1,val[i])-san;
dfs(1);
scanf("%d",&q);
for(int i=0;i<q;i++) {
scanf("%d",&Q[i].v);
Q[i].l=L[Q[i].v];
Q[i].r=R[Q[i].v];
Q[i].id=i;
}
sort(Q,Q+q);
build(1,tot,1);
int pt=0;
for(int i=1;i<=tot;i++) {
int value = num[i];
pos[value].push_back(i);
int sz=pos[value].size();
if(sz >= k) {
if(sz > k) {
update(1,pos[value][sz-k-1],-1,1,tot,1);
update(pos[value][sz-k-1]+1,pos[value][sz-k],1,1,tot,1);
}
else update(1,pos[value][sz-k],1,1,tot,1);
}
while(pt < q && Q[pt].r == i) {
ans[Q[pt].id] = query(Q[pt].l,1,tot,1);
pt++;
}
}
if(ca) puts("");
printf("Case #%d:\n",++ca);
for(int i=0;i<q;i++) printf("%d\n",ans[i]);
}
return 0;
}