CF375D Tree and Queries

题意简述

给一个(n)个节点的树,根节点为(1),第(i)个节点有一个颜色(c_i),有(m)个询问,每个询问:

(u,k),求以(u)为根的子树出现次数(ge k)的颜色个数。

(n,m,k,c_i le 10^5)

简单口胡

好像正解是(nlog{n})的?我不会。

我整的是(nsqrt{n})的。

不难想到将树转成( ext{dfn})序,然后以(u)为子树的( ext{dfn})序即为([ ext{dfn}_u, ext{dfn}_u + ext{siz}_u - 1]),其中( ext{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
",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
",ans[i]);
    return 0;
}
原文地址:https://www.cnblogs.com/luyiming123blog/p/CF375D.html