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;
}
posted @ 2020-11-28 18:15  luyiming123  阅读(79)  评论(0编辑  收藏  举报