• 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
    ",ans[i]);
    	return 0;
    }
    

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

      

  • 相关阅读:
    MySQL中的char与varchar详解
    有关PHPstorm的git环境的配置和git密钥的生成总结
    PHP开发中常用的字符串操作函数
    PHP 二维数组排序函数的应用 array_multisort()
    大龄程序员的出路在哪里
    近期面试总结(PHP后端开发工程师)(部分笔试题)
    B-Tree目录和Hash索引的区别
    curl、fopen和file_get_contents区别
    什么是OAuth授权
    SEO 统计算法
  • 原文地址:https://www.cnblogs.com/X-rice/p/11218719.html
Copyright © 2020-2023  润新知