• [Codeforces Round #221 (Div. 1)][D. Tree and Queries]


    题目链接:375D - Tree and Queries

    题目大意:给你一个有n个点的树,每个点都有其对应的颜色,给出m次询问(v,k),问v的子树中有多少种颜色至少出现k次

    题解:先对所有的询问进行分类,即对所有相同的v合并到一起,这样就能转为离线处理(更新每个点的状态时同时求出答案)

       开两个map<int,int>,cnt[i][j]表示 i 节点的子树中 j 颜色出现了多少次,f[i][j]则表示 i 节点的子树中至少出现 j 次的颜色个数。dfs的时候暴力枚举所有颜色合并能够得出正确答案,但这样做显然会TLE,因此需要用到启发式合并进行优化。即每次合并的时候是将小的集合并到大的集合中去,这样做的话就只需要枚举小集合里的元素,可以将合并的时间复杂度缩减到O(log n)的级别

    #include<bits/stdc++.h>
    using namespace std;
    #define N 100001
    int n,m,u,v,c[N],k[N],ans[N];
    map<int,int>cnt[N],f[N];
    vector<int>d[N],q[N];
    void dfs(int cur,int pre)
    {
        cnt[cur][c[cur]]++,f[cur][1]++;
        for(auto nxt:d[cur])if(nxt!=pre)
          {
          dfs(nxt,cur);
          if(cnt[nxt].size()>cnt[cur].size())
            cnt[cur].swap(cnt[nxt]),f[cur].swap(f[nxt]);
          for(auto x:cnt[nxt])
            {
            int y=cnt[cur][x.first];
            cnt[cur][x.first]+=x.second;
            for(int i=y+1;i<=y+x.second;i++)f[cur][i]++;
            }
          }
        for(auto i:q[cur])ans[i]=f[cur][k[i]];
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
          scanf("%d",&c[i]);
        for(int i=2;i<=n;i++)
          {
          scanf("%d%d",&u,&v);
          d[u].push_back(v);
          d[v].push_back(u);
          }
        for(int i=1;i<=m;i++)
          scanf("%d%d",&v,&k[i]),q[v].push_back(i);
        dfs(1,0);
        for(int i=1;i<=m;i++)
          printf("%d
    ",ans[i]);
    }
    View Code
  • 相关阅读:
    Java中List集合去除重复数据的方法
    ActiveMQ消息中间件Producer和Consumer
    JMS Activemq实战例子demo
    利用正则表达式判断输入内容是否全中文
    纯js的右下角弹窗
    java开源项目
    linux部署jdk-tomcat
    你的主机中的软件中止了一个已建立的连接。
    Centos编译安装 LAMP (apache-2.4.7 + mysql-5.5.35 + php 5.5.8)+ Redis
    在LAMP的生产环境内添加PHP的cURL扩展模块
  • 原文地址:https://www.cnblogs.com/DeaphetS/p/9573428.html
Copyright © 2020-2023  润新知