CF375D Tree and Queries

题目大意:给出一棵 n 个结点的树,每个结点有一个颜色 c[i]。 询问 q 次,每次询问以 v 结点为根的子树中,出现次数 ≥k 的颜色有多少种。树的根节点是1。 (1<=c[i],n,m<=100000)。

思路:这是一道树上问题转成序列问题的题目,我们先利用dfs序将树上问题变成序列问题,然后我们的问题就变成了:在1个序列内,询问q次,每次询问[l,r]中颜色出现次数大于等于k的颜色有多少种。我们可以用莫队来维护他,将每个l 按照所处块为第一关键字,右端点为第二关键字排序,然后开个桶记录颜色出现次数,再开个ans[i]记录颜色等于i的数量(当然也可以用树状数组维护,复杂度多个log,应该能过),因为莫队每次移动只会使ans数组+1或-1,所以大于等于i的颜色必定会经过ans[i],那么最后的答案也就是ans[i];复杂度O(n·log(n))。

代码如下:

 

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int MaxN=200000;
struct edge{
	int to,next;
}e[MaxN*2];
struct node{
	int bel,l,r,id,k;
}M[MaxN];
int n,m,las,tto,a[MaxN],b[MaxN],last[MaxN],tot[MaxN],pd[MaxN];
int id,dfn[MaxN],bel[MaxN],siz[MaxN],numb[MaxN],ans[MaxN];
void add_edge(int x,int y){
	e[++tto].to=y;e[tto].next=last[x];last[x]=tto;
	return;
}
void dfs(int x,int f){
	siz[x]=1;dfn[x]=++id;bel[id]=x;
	for(int i=last[x];i;i=e[i].next){
		int u=e[i].to;
		if(u==f) continue;
		dfs(u,x);siz[x]+=siz[u];
	}
	return;
}
int cmp(node a,node b){
	return a.bel==b.bel?a.r<b.r:a.bel<b.bel;//!
}
int main(){
	int x,y,v,k;
	scanf("%d%d",&n,&m);int s=sqrt(n);
	for(int i=1;i<=n;++i) scanf("%d",&a[i]);
	for(int i=1;i<n;++i) scanf("%d%d",&x,&y),add_edge(x,y),add_edge(y,x);
	dfs(1,0);for(int i=1;i<=n;++i) b[i]=a[bel[i]];
	for(int i=1;i<=m;++i){
		scanf("%d%d",&v,&k);
		M[i].bel=dfn[v]/s;M[i].l=dfn[v];M[i].r=dfn[v]+siz[v]-1;M[i].id=i;M[i].k=k;
	}
	sort(M+1,M+m+1,cmp);
	int ll=M[1].l,lr=M[1].r;
	for(int i=ll;i<=lr;++i){
		tot[b[i]]++;numb[tot[b[i]]]++;
	}
	ans[M[1].id]=numb[M[1].k];
	for(int i=2;i<=m;++i){
		int nl=M[i].l,nr=M[i].r;
		while(ll<nl) numb[tot[b[ll]]]--,tot[b[ll]]--,++ll;
		while(ll>nl) tot[b[--ll]]++,numb[tot[b[ll]]]++;
		while(lr<nr) tot[b[++lr]]++,numb[tot[b[lr]]]++;
		while(lr>nr) numb[tot[b[lr]]]--,tot[b[lr]]--,--lr;
		ans[M[i].id]=numb[M[i].k];
	}
	for(int i=1;i<=m;++i) printf("%d\n",ans[i]);
	return 0;
}

 题外话:这是我比赛时遇到的题,当时树上莫队打出来了,结果排序时以左端点为第二关键字被卡常了90分qwq

  

 

posted @ 2019-07-20 18:30  X_rice  阅读(94)  评论(0编辑  收藏  举报