CF375D Tree and Queries
题意简述
给一个\(n\)个节点的树,根节点为\(1\),第\(i\)个节点有一个颜色\(c_i\),有\(m\)个询问,每个询问:
给\(u,k\),求以\(u\)为根的子树出现次数\(\ge k\)的颜色个数。
\(n,m,k,c_i \le 10^5\)
简单口胡
好像正解是\(n\log{n}\)的?我不会。
我整的是\(n\sqrt{n}\)的。
不难想到将树转成\(\text{dfn}\)序,然后以\(u\)为子树的\(\text{dfn}\)序即为\([\text{dfn}_u,\text{dfn}_u + \text{siz}_u - 1]\),其中\(\text{siz}_u\)指以\(u\)为根的子树的大小(包括\(u\))。
然后莫队既珂。
# include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 2;
int n,m;
int c[N];
// int l[1010],r[1010];
int dfn[N],dfn2[N],siz[N];
int son[N];
int Q[N],QQ[N];
int ans[N];
int C[N];
int len,num,dfntot = 0;
struct node
{
int l,r,k,soc;
}q[N];
vector <int> g[N];
int belong(int x)
{
return (x - 1) / len + 1;
}
bool compare(const struct node &a,const struct node &b)
{
return belong(a.l) ^ belong(b.l) ? (belong(a.l) < belong(b.l)) : (belong(a.l) & 1) ? a.r < b.r : a.r > b.r;
}
void dfs(int x,int fa)
{
// printf("%d\n",x);
dfn[x] = ++dfntot;
siz[x] = 1;
C[dfn[x]] = c[x];
for(int i = 0; i < g[x].size(); i++)
{
int v = g[x][i];
if(v != fa)
{
dfs(v,x);
siz[x] += siz[v];
if(siz[v] > siz[son[x]]) son[x] = v;
}
}
dfn2[x] = dfntot;
return;
}
// void dfs2(int x,int fa)
// {
// dfn[x] = ++dfntot;
// if(son[x]) dfs2(son[x],x);
// for(auto v : g[x])
// {
// if(v != fa && v != son[x]) dfs2(v,x);
// }
// }
void Del(int x)
{
// QQ[Q[c[x]]]--;
--QQ[Q[C[x]]--];
}
void Add(int x)
{
++QQ[++Q[C[x]]];
// QQ[--Q[c[x]]]++;
}
int main(void)
{
scanf("%d%d",&n,&m);
len = sqrt(n),num = (n - 1) / len + 1;
for(int i = 1; i <= n; i++)
{
scanf("%d",&c[i]);
}
for(int i = 1; i < n; i++)
{
int u,v;
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1,0);
// dfs2(1,0);
for(int i = 1; i <= m; i++)
{
int u;
scanf("%d%d",&u,&q[i].k);
q[i].l = dfn[u],q[i].r = dfn2[u];
q[i].soc = i;
}
sort(q + 1, q + m + 1,compare);
int L = 1,R = 0;
for(int i = 1; i <= m; i++)
{
while(L < q[i].l)
{
Del(L++);
}
while(R > q[i].r)
{
Del(R--);
}
while(L > q[i].l)
{
Add(--L);
}
while(R < q[i].r)
{
Add(++R);
}
ans[q[i].soc] = QQ[q[i].k];
}
for(int i = 1; i <= m; i++) printf("%d\n",ans[i]);
return 0;
}