传送门
搞一个dfs序然后就变成了询问一坨区间
莫队
刚开始写了个bit结果tle
实际上写一个分块,维护块内和,然后 O(1) 修改 O(n√) 查询就可以了
因为
ATP:修改次数非常多,能达到 nn√ ,但是查询次数不会超过 m
#include
#include
#include
#include
#include
using namespace std;
#define N 200005
int n,m,x,y,dfs_clock,block,t;
int tot,point[N],nxt[N*2],v[N*2];
int in[N],out[N],pt[N],cnt[N],c[N],a[N],sum[N];
struct data{int k,l,r,id,ans;}q[N];
int L[N],R[N],num[N];
void add(int x,int y)
{
++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
}
void dfs(int x,int fa)
{
in[x]=++dfs_clock;pt[dfs_clock]=x;
for (int i=point[x];i;i=nxt[i])
if (v[i]!=fa)
dfs(v[i],x);
out[x]=dfs_clock;
}
int cmp(data a,data b)
{
return num[a.l]int x,int val)
{
sum[num[x]]-=a[x];
a[x]+=val;
sum[num[x]]+=a[x];
}
int query(int x)
{
int ans=0;
if (x>n) return ans;
if (x==L[num[x]]) x=num[x];
else
{
for (int i=x;i<=R[num[x]];++i) ans+=a[i];
x=num[x]+1;
}
for (int i=x;i<=t;++i) ans+=sum[i];
return ans;
}
void modui(int l,int r,int f)
{
for (int i=l;i<=r;++i)
{
int x=pt[i];
if (cnt[c[x]]) change(cnt[c[x]],-1);
cnt[c[x]]+=f;
if (cnt[c[x]]) change(cnt[c[x]],1);
}
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;++i) scanf("%d",&c[i]);
for (int i=1;i"%d%d",&x,&y);
add(x,y),add(y,x);
}
dfs(1,0);
for (int i=1;i<=m;++i)
{
scanf("%d%d",&x,&q[i].k);
q[i].l=in[x],q[i].r=out[x];q[i].id=i;
}
block=sqrt(n);t=(n-1)/block+1;
for (int i=1;i<=n;++i) num[i]=(i-1)/block+1;
L[1]=1,R[1]=block;
for (int i=2;i<=t;++i) L[i]=L[i-1]+block,R[i]=R[i-1]+block;R[t]=n;
sort(q+1,q+m+1,cmp);
modui(q[1].l,q[1].r,1);
q[q[1].id].ans=query(q[1].k);
for (int i=2;i<=m;++i)
{
if (q[i-1].l<q[i].l) modui(q[i-1].l,q[i].l-1,-1);
else modui(q[i].l,q[i-1].l-1,1);
if (q[i-1].r<q[i].r) modui(q[i-1].r+1,q[i].r,1);
else modui(q[i].r+1,q[i-1].r,-1);
q[q[i].id].ans=query(q[i].k);
}
for (int i=1;i<=m;++i) printf("%d\n",q[i].ans);
}