zoukankan      html  css  js  c++  java
  • Codeforces 375D

    题目链接:http://codeforces.com/contest/351/problem/D

    题目大意:n个数,col[i]对应第i个数的颜色,并给你他们之间的树形关系(以1为根),有m次询问,每次给出vi,ki,要求找出以点vi为根的子树上出现超过ki次的颜色数。

    解题思路:这题显然是可以用莫队写的,只要在开一个数组cnk[i]记录出现次数超过i次的颜色数即可,但是要先进行“将树化为线段的操作”,之前写的一道线段树也用了dfs序的方法使得多叉树化为线段:链接,这里就不多说了。要注意的是使用dfs划线的过程中记得要把对应序号的颜色也映射到线段上。

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<vector>
     4 #include<cstdio>
     5 #include<cmath>
     6 using namespace std;
     7 const int N=1e5+5;
     8 int num;
     9 int unit;
    10 int arr[N],col[N],cnt[N],cnk[N],res[N],Start[N],End[N],vis[N];//cnk[i]表示至少出现i次的颜色数 
    11 vector<int>v[N];
    12 
    13 struct node{
    14     int l,r,kj;
    15     int id;
    16 }q[N];
    17 
    18 //将树化为区间 
    19 void dfs(int rt){
    20     Start[rt]=++num;
    21     //**将对应序号的颜色映射到新的线段上 
    22     arr[num]=col[rt];
    23     vis[rt]=1;
    24     for(int i=0;i<v[rt].size();i++){
    25         if(!vis[v[rt][i]])
    26             dfs(v[rt][i]);
    27     }
    28     End[rt]=num;
    29 } 
    30 
    31 bool cmp(node a,node b){
    32     return a.l/unit==b.l/unit?a.r<b.r:a.l/unit<b.l/unit;
    33 }
    34 
    35 void add(int pos){
    36     cnt[arr[pos]]++;
    37     cnk[cnt[arr[pos]]]++;
    38 }
    39 
    40 void remove(int pos){
    41     cnk[cnt[arr[pos]]]--;
    42     cnt[arr[pos]]--;    
    43 }
    44 
    45 int main(){
    46     int n,m;
    47     scanf("%d%d",&n,&m);
    48     unit=sqrt(n);
    49     for(int i=1;i<=n;i++){
    50         scanf("%d",&col[i]);
    51     }
    52     for(int i=1;i<=n-1;i++){
    53         int a,b;
    54         scanf("%d%d",&a,&b);
    55         //**题目没有直接说明a,b从属关系所以建立双向邻接表 
    56         v[a].push_back(b);
    57         v[b].push_back(a);
    58     }
    59     //以1为根 
    60     dfs(1);
    61     
    62     for(int i=1;i<=m;i++){
    63         int vj,kj;
    64         scanf("%d%d",&vj,&kj);
    65         q[i].kj=kj;
    66         q[i].id=i;
    67         q[i].l=Start[vj];
    68         q[i].r=End[vj];
    69     }
    70     sort(q+1,q+1+m,cmp);
    71     int L=q[1].l,R=L-1;
    72     for(int i=1;i<=m;i++){
    73         while(L>q[i].l)
    74             add(--L);
    75         while(L<q[i].l)
    76             remove(L++);
    77         while(R<q[i].r)
    78             add(++R);
    79         while(R>q[i].r)
    80             remove(R--);
    81         res[q[i].id]=cnk[q[i].kj];
    82     }
    83     for(int i=1;i<=m;i++){
    84         printf("%d
    ",res[i]);
    85     }
    86 }
    87  
  • 相关阅读:
    算法与数据结构实验题 5.2 Missile
    算法与数据结构实验题 2.3 击鼓传花
    算法与数据结构实验题 2.4 排队
    Linux 添加自定义命令
    转 32位linux内核2.6.38.2添加系统调用,编写类似"ps"命令模块显示进程信息
    Linux内核模块程序加载方法
    Linux下sched.h文件分析
    Kali 爆破和非爆破无线路由账号和密码+让别人无线掉线
    Kali基于路由器的ARP欺骗转发机制
    Kali nmap教程用法简介
  • 原文地址:https://www.cnblogs.com/fu3638/p/7201252.html
Copyright © 2011-2022 走看看