题解:莫队+分块
对于出现次数也分块维护,每次O(sqrt(n))查询
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define N 500003
using namespace std;
int n,m,c[N],a[N],belong[N],l[N],r[N],ans[N];
int tot,point[N],v[N],nxt[N],sz,cnt[N],num[N],block;
struct data{
int l,r,k,id;
}q[N];
int cmp(data a,data b)
{
return belong[a.l]<belong[b.l]||belong[a.l]==belong[b.l]&&a.r<b.r;
}
void add(int x,int y)
{
tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
tot++; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;
}
void dfs(int x,int fa)
{
a[++sz]=c[x]; l[x]=sz;
for (int i=point[x];i;i=nxt[i]){
if (v[i]==fa) continue;
dfs(v[i],x);
}
r[x]=sz;
}
void addx(int x,int val)
{
num[belong[x]]-=v[x];
v[x]+=val;
num[belong[x]]+=v[x];
}
void change(int pos,int val)
{
int t=a[pos];
if (cnt[t]) addx(cnt[t],-1);
cnt[t]+=val;
if (cnt[t]) addx(cnt[t],1);
}
int query(int l,int r)
{
int t=0;
if (belong[l]==belong[r]){
for (int i=l;i<=r;i++)
if (v[i]) t+=v[i];
return t;
}
for (int i=l;i<=belong[l]*block;i++)
if (v[i]) t+=v[i];
for (int i=(belong[r]-1)*block+1;i<=r;i++)
if (v[i]) t+=v[i];
for (int i=belong[l]+1;i<belong[r];i++)
t+=num[i];
return t;
}
int main()
{
freopen("a.in","r",stdin);
freopen("my.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%d",&c[i]);
for (int i=1;i<n;i++) {
int x,y; scanf("%d%d",&x,&y);
add(x,y);
}
dfs(1,0); block=ceil(sqrt(n));
for (int i=1;i<=n;i++) belong[i]=(i-1)/block+1;
int mx=0;
for (int i=1;i<=m;i++) {
scanf("%d%d",&q[i].l,&q[i].k),q[i].id=i;
q[i].r=r[q[i].l]; q[i].l=l[q[i].l];
mx=max(mx,q[i].k);
}
mx=max(mx,n);
memset(v,0,sizeof(v));
sort(q+1,q+m+1,cmp);
block=ceil(sqrt(mx));
for (int i=1;i<=mx;i++) belong[i]=(i-1)/block+1;
int l=1,r=1; change(1,1);
for (int i=1;i<=m;i++) {
while (q[i].l<l) change(--l,1);
while (q[i].l>l) change(l++,-1);
while (q[i].r>r) change(++r,1);
while (q[i].r<r) change(r--,-1);
ans[q[i].id]=query(q[i].k,mx);
}
for (int i=1;i<=m;i++) printf("%d\n",ans[i]);
}