1. 程式人生 > 其它 >【CF375D】Tree and Queries

【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;
}