zoukankan      html  css  js  c++  java
  • POJ 2104 第K大的数, 主席树,

        第一次接触这种神奇的数据结构,感觉不错。有学了个好东西,也不难。他主要应该是针对于数据统计的,例如本题的第k大的数。算法的主要思想是 先对给定的数离散化,然后在线段树中保存数字出现的次数(即叶子节点会存该节点所对应的数字出现的次数,非叶结点则保存子节点的数字之和)(这就与我们普通的线段树不同了)。然后我们会对于 从 a1 到 ai ( 1<=i<=n )之间的数据建一棵线段树,因此总共会建n+1棵,(看到这,你会不会担心MLE呢?其实不会的,因为节点是可以共用的)。 建完后,如果 查询是针对 ai 到 aj 这个区间的,那么我们就可以用aj那棵线段树上的值减去 ai-1 那棵线段树上的值,那么就可以得到在这个区间中各个数字出现的次数。加油!

    真奇怪,为什么 POJ 上写read(),读入优化反而慢了700多毫秒。求大神赐教。

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<algorithm>
     4 #define rep(i,j,k) for(int i = j; i <= k; i++)
     5 using namespace std;
     6 int root[100005], a[100005], p[100005];
     7 int n_nodes = 0, n_numb;
     8 
     9 struct node{
    10 int times, lc, rc;
    11 } nod[3000000];
    12 
    13 void build(int l,int r,int&p){
    14     p = ++n_nodes;
    15     nod[p].lc = nod[p].rc = nod[p].times = 0;
    16     if( l >= r ) return;
    17     int mid = (l+r)/2;
    18     build(l,mid,nod[p].lc); build(mid+1,r,nod[p].rc);
    19 }
    20 
    21 void build2(int l,int r,int&p, int pre,int mre)
    22 {
    23     p = ++n_nodes;
    24     nod[p] = nod[pre];
    25     nod[p].times++;
    26     if( l >= r ) return;
    27     int mid = (l+r)/2;
    28     if( mre <= mid ){
    29         build2(l,mid,nod[p].lc,nod[pre].lc,mre);
    30     }    
    31     else {
    32         build2(mid+1,r,nod[p].rc,nod[pre].rc,mre);
    33     }
    34 }
    35 
    36 int ask(int l,int r,int pre,int p,int k)
    37 {
    38     if( l >= r ) return l;
    39     int s = nod[nod[p].lc].times - nod[nod[pre].lc].times;
    40     int mid = (l+r) / 2;
    41     if( s >= k ){
    42         return ask(l,mid,nod[pre].lc,nod[p].lc,k);
    43     }
    44     else {
    45         return ask(mid+1,r,nod[pre].rc,nod[p].rc,k-s);
    46     }
    47 }
    48 
    49 int main()
    50 {
    51     int n, q;
    52     scanf("%d %d",&n,&q);
    53     rep(i,1,n){
    54         scanf("%d", &a[i]);
    55         p[i] = a[i];
    56     }
    57     sort(p+1,p+1+n);
    58     n_numb = unique(p+1,p+1+n) - p - 1;
    59     build(1,n_numb,root[0]);
    60     rep(i,1,n){
    61         int m = lower_bound(p+1,p+n_numb+1,a[i]) - p;
    62         build2(1,n_numb,root[i],root[i-1],m);
    63     }
    64     rep(i,1,q){
    65         int x, y, k;
    66         scanf("%d %d %d",&x,&y,&k);
    67         int m = ask(1,n_numb,root[x-1],root[y],k);
    68         printf("%d
    ", p[m]);
    69     }
    70     return 0;
    71 }
    人一我十,人十我万!追逐青春的梦想,怀着自信的心,永不放弃!仿佛已看到希望,尽管还在远方
  • 相关阅读:
    Linux查看日志常用命令
    linux(centos)下安装PHP的PDO扩展
    TP thinkphp 权限管理 权限认证 功能
    mysql优化(三)–explain分析sql语句执行效率
    阿里云服务器Centos7成为挖矿肉鸡被挖矿imWBR1耗尽CPU
    Asp.net导入Excel并读取数据
    定义显式类型转换和隐式类型转换
    C# 对象与引用变量
    C# ref参数
    C# 字段与属性的区别
  • 原文地址:https://www.cnblogs.com/83131yyl/p/5085520.html
Copyright © 2011-2022 走看看