题目
题目链接: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;
}