• 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;
    }
    
  • 相关阅读:
    什么是shell
    Jenkins+python+selenium持续继承自动化测试
    selenium+python自动化
    产品和项目的概念
    继承与派生:赋值兼容规则(转)
    继承与派生:虚基类及其派生类的构造函数(转)
    重载函数与函数模板(转)
    继承与派生:作用域分辨符(转)
    作用域和可见性(转)
    继承与派生:派生类的析构函数(转)
  • 原文地址:https://www.cnblogs.com/luyiming123blog/p/CF375D.html
Copyright © 2020-2023  润新知