CF375D Tree and Queries

题目

luogu

思路

唯有水题暖人心
只用子树的树,当然dfs序列
区间查询出现k次的数字的个数
nub[i]记录出现次数大于i的数字个数
发现只是O(1)的转移,想想就OK了

代码

ps:为了更好地阅读,我加一段cpp吧

void add(int x)
{	
	hav[x]++;
	nub[hav[x]]++;
}
void delet(int x)
{
	nub[hav[x]]--;
	hav[x]--;
}
FOR(i,1,m)
{
	while(l > Q[i].s) add(a[b[--l]]);
	while(l < Q[i].s) delet(a[b[l++]]);
	while(r < Q[i].t) add(a[b[++r]]);
	while(r > Q[i].t) delet(a[b[r--]]);
	Q[i].ans=nub[Q[i].k];
}
#include <bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;++i)
using namespace std;
const int maxn=1e5+7;
int n,m,a[maxn],b[maxn],begg[maxn],endd[maxn],js,nub[maxn],hav[maxn];;
int head[maxn<<1],tot,belong[maxn];
struct node
{
	int s,t,k,id,ans;
}Q[maxn];
bool cmp1(const node &a,const node &b){	return belong[a.s]==belong[b.s] ? a.t<b.t : a.s<b.s;}
bool cmp2(const node &a,const node &b){	return a.id<b.id;}
struct edge
{
	int v,nxt;
}e[maxn<<1];
void add_edge(int u,int v)
{
	e[++tot].v=v;
	e[tot].nxt=head[u];
	head[u]=tot;
}
int read()
{
	int x=0,f=1;char s=getchar();
	for(;s<'0'||s>'9';s=getchar()) if(s=='-') f=-1;
	for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0';
	return x*f;
}
void dfs(int u,int f)
{
	b[++js]=u;
	begg[u]=js;
	for(int i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].v;
		if(v==f) continue;
		dfs(v,u);
	}
	endd[u]=js;
}
int main()
{
	n=read(),m=read();
	int k=sqrt(n);
	FOR(i,1,n) a[i]=read();
	FOR(i,1,n) belong[i]=(i-1)/k+1;
	FOR(i,1,n-1)
	{
		int x=read(),y=read();
		add_edge(x,y);
		add_edge(y,x);
	}
	dfs(1,0);
	FOR(i,1,m)
	{
		int x=read(),y=read();
		Q[i].s=begg[x];
		Q[i].t=endd[x];
		Q[i].k=y;
		Q[i].id=i;
	}
	sort(Q+1,Q+1+m,cmp1);
	int l=1,r=0;
	FOR(i,1,m)
	{
		while(l > Q[i].s) hav[a[b[--l]]]++,nub[hav[a[b[l]]]]++;
		while(l < Q[i].s) nub[hav[a[b[l]]]]--,hav[a[b[l++]]]--;
		while(r < Q[i].t) hav[a[b[++r]]]++,nub[hav[a[b[r]]]]++;
		while(r > Q[i].t) nub[hav[a[b[r]]]]--,hav[a[b[r--]]]--;
		Q[i].ans=nub[Q[i].k];
	}
	sort(Q+1,Q+1+m,cmp2);
	FOR(i,1,m) printf("%d\n",Q[i].ans);
}
posted @ 2018-10-18 20:12  ComplexPug  阅读(119)  评论(1编辑  收藏  举报