[cf375D]Tree and Queries

Description

给定一棵树,每个节点有颜色。t个询问,求以v为根的子树中有多少种颜色满足该颜色的节点个数>k。

Solution

dfs序+莫队。

#include<bits/stdc++.h>
using namespace std;
const int N=100005;
struct graph{
int nxt,to;
}e[N<<1];
struct query{
int l,r,k,n;
}q[N];
int fro[N],beh[N],num[N];//dfs序
int f[N],s[N],tmp[N];//莫队 tmp[i]:s[x]>=i的x的个数
int g[N],c[N],ans[N],n,m,t,cnt;
void adde(int x,int y){
e[++cnt].nxt=g[x];g[x]=cnt;e[cnt].to=y;
}
void dfs(int u){
fro[u]=++cnt;num[cnt]=u;
for(int i=g[u];i;i=e[i].nxt)
if(!fro[e[i].to]){
dfs(e[i].to);
}
beh[u]=cnt;
}
bool cmp(query a,query b){
if(f[a.l]!=f[b.l]) return f[a.l]<f[b.l];
return a.r<b.r;
}
void add(int i){
++s[c[num[i]]];
++tmp[s[c[num[i]]]];
}
void remove(int i){
--tmp[s[c[num[i]]]];
--s[c[num[i]]];
}
int main(){
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
scanf("%d%d",&n,&t);
for(int i=1;i<=n;++i)
scanf("%d",&c[i]);
for(int i=1,x,y;i<n;++i){
scanf("%d%d",&x,&y);
adde(x,y);adde(y,x);
}
cnt=0;dfs(1);
for(int i=1,v;i<=t;++i){
scanf("%d%d",&v,&q[i].k);
q[i].l=fro[v];q[i].r=beh[v];q[i].n=i;
}
m=sqrt(n);
for(int i=1,k=1;i<=n;++k)
for(int j=1;i<=n&&j<=m;++i,++j)
f[i]=k;
sort(q+1,q+1+t,cmp);
int l=1,r=1;
++s[c[num[1]]];++tmp[1];
for(int i=1;i<=t;++i){
while(r<q[i].r){
++r;add(r);
}
while(r>q[i].r){
remove(r);--r;
}
while(l>q[i].l){
--l;add(l);
}
while(l<q[i].l){
remove(l);++l;
}
ans[q[i].n]=tmp[q[i].k];
}
for(int i=1;i<=t;++i)
printf("%d\n",ans[i]);
return 0;
}
posted @   Aireen_Ye  阅读(51)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
历史上的今天:
2017-01-06 [模板]平面最近点对
底部 顶部 留言板 归档 标签
Der Erfolg kommt nicht zu dir, du musst auf den Erfolg zugehen.



点击右上角即可分享
微信分享提示