CF375D Tree and Queries

题目

给定一棵 \(n\) 个节点的树,根节点为 1。每个节点上有一个颜色 \(c_i\)
\(m\) 次操作。操作有一种:\(u\) \(k:\) 询问在以 \(u\) 为根的子树中,出现次数 \(\ge k\) 的颜色有多少种。
\(2 \le n \le 10^5 , 1 \le m \le 10^5 ,1 \le c_i,k \le 10^5\)

分析

树上启发式合并即可

\(Code\)

#include<cstdio>
#include<vector>
using namespace std;

const int N = 1e5 + 5;
int n , m , tot , dfc;
int cnt[N] , sum[N] , siz[N] , rev[N] , dfn[N] , col[N] , h[N] , son[N] , ans[N]; 

struct node{
	int k , id;
};
vector<node> q[N];

struct edge{
	int nxt , to;
}e[N * 2];
inline void add(int x , int y){e[++tot] = edge{h[x] , y} , h[x] = tot;}

void dfs1(int x , int fa)
{
	siz[x] = 1 , dfn[x] = ++dfc , rev[dfc] = x;
	for(register int i = h[x]; i; i = e[i].nxt)
	{
		int v = e[i].to;
		if (v == fa) continue;
		dfs1(v , x) , siz[x] += siz[v];
		son[x] = siz[son[x]] < siz[v] ? v : son[x];
	} 
}

void dfs2(int x , int fa , int kp)
{
	for(register int i = h[x]; i; i = e[i].nxt)
	{
		int v = e[i].to;
		if (v == fa || v == son[x]) continue;
		dfs2(v , x , 0);
	}
	if (son[x]) dfs2(son[x] , x , 1);
	++sum[++cnt[col[x]]];
	for(register int i = h[x]; i; i = e[i].nxt)
	{
		int v = e[i].to;
		if (v == fa || v == son[x]) continue;
		for(register int j = dfn[v]; j <= dfn[v] + siz[v] - 1; j++)
			++cnt[col[rev[j]]] , ++sum[cnt[col[rev[j]]]];
	}
	for(register int i = 0; i < q[x].size(); i++) ans[q[x][i].id] = sum[q[x][i].k];
	if (!kp)
	{
		for(register int i = dfn[x]; i <= dfn[x] + siz[x] - 1; i++) 
			--sum[cnt[col[rev[i]]]] , --cnt[col[rev[i]]];
	}
}

int main()
{
	scanf("%d%d" , &n , &m);
	for(register int i = 1; i <= n; i++) scanf("%d" , &col[i]);
	int x , y;
	for(register int i = 1; i < n; i++) 
		scanf("%d%d" , &x , &y) , add(x , y) , add(y , x);
	for(register int i = 1; i <= m; i++) 
		scanf("%d%d" , &x , &y) , q[x].push_back(node{y , i});
	dfs1(1 , 0) , dfs2(1 , 0 , 1);
	for(register int i = 1; i <= m; i++) printf("%d\n" , ans[i]);
} 
posted @ 2020-11-05 19:42  leiyuanze  阅读(55)  评论(0编辑  收藏  举报