【CF375D】Tree and Queries

题目

题目链接:https://codeforces.com/problemset/problem/375/D
给定一棵 \(n\) 个节点的有根树,节点有颜色,\(m\) 次询问一个点的子树内出现次数 \(\geq k\) 的颜色数有多少。
\(n\leq 10^5\)

思路

dsu on tree 板子题。
本来太板子不想写的,但是因为太久没写了就水了一道题。
直接维护一个桶表示出现次数等于下标的颜色数量即可。
时间复杂度 \(O(n\log n+m)\)

代码

#include <bits/stdc++.h>
#define mp make_pair
#define fi first
#define se second
using namespace std;

const int N=100010;
int n,m,tot,head[N],a[N],cnt[N],sum[N],ans[N],siz[N],son[N],id[N],rk[N];
vector<pair<int,int> > ask[N];

struct edge
{
	int next,to;
}e[N*2];

void add(int from,int to)
{
	e[++tot]=(edge){head[from],to};
	head[from]=tot;
}

void dfs1(int x,int fa)
{
	siz[x]=1;
	for (int i=head[x];~i;i=e[i].next)
	{
		int v=e[i].to;
		if (v!=fa)
		{
			dfs1(v,x); siz[x]+=siz[v];
			if (siz[v]>siz[son[x]]) son[x]=v;
		}
	}
}

void dfs2(int x,int fa,bool flag)
{
	id[x]=++tot; rk[tot]=x;
	for (int i=head[x];~i;i=e[i].next)
	{
		int v=e[i].to;
		if (v!=fa && v!=son[x]) dfs2(v,x,1);
	}
	if (son[x]) dfs2(son[x],x,0);
	cnt[a[x]]++; sum[cnt[a[x]]]++;
	if (son[x])
		for (int i=id[x]+1;i<id[son[x]];i++)
			cnt[a[rk[i]]]++,sum[cnt[a[rk[i]]]]++;
	for (int i=0;i<ask[x].size();i++)
		ans[ask[x][i].se]=sum[ask[x][i].fi];
	if (flag)
		for (int i=id[x];i<id[x]+siz[x];i++)
			sum[cnt[a[rk[i]]]]--,cnt[a[rk[i]]]--;
}

int main()
{
	memset(head,-1,sizeof(head));
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for (int i=1,x,y;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		add(x,y); add(y,x);
	}
	for (int i=1,x,y;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		ask[x].push_back(mp(y,i));
	}
	tot=0; 
	dfs1(1,0); dfs2(1,0,1);
	for (int i=1;i<=m;i++) cout<<ans[i]<<"\n";
	return 0;
}
posted @ 2021-06-15 14:30  stoorz  阅读(34)  评论(0编辑  收藏  举报