• 主席树模板


    简述:

      解决线段树无法求区间第k大的问题

    代码:

      1 ///主席树模版(查询区间第k大)
      2 #include <cstdio>
      3 #include <cstdlib>
      4 #include <cstring>
      5 #include <algorithm>
      6 #include <cctype>
      7 #define numm ch-48
      8 #define pn putchar('
    ')
      9 #define pd putchar(' ')
     10 //#define debug(args...) cout<<#args<<"->"<<args<<endl
     11 //#define bug cout<<"*******************"<<endl
     12 using namespace std;
     13 template<typename T>
     14 void read(T &res) {
     15     char ch;bool flag=false;
     16     while(!isdigit(ch=getchar()))(ch=='-')&&(flag=true);
     17     for(res=numm;isdigit(ch=getchar());res=(res<<1)+(res<<3)+numm);
     18     flag&&(res=-res);
     19 }
     20 template<typename T>
     21 void write(T x) {
     22     if(x<0) x=-x,putchar('-');
     23     if(x>9) write(x/10);
     24     putchar(x%10+48);
     25 }
     26 typedef long long ll;
     27 const int maxn=100010+10;
     28 const int inf=0x3f3f3f3f;
     29 struct bb {
     30     int x,pos;
     31     bool operator<(const bb& c) {
     32         return x==c.x?pos<c.pos:x<c.x;
     33     }
     34 }b[maxn];
     35 struct node {
     36     int l,r;    ///当前结点的管辖范围
     37     int zuo,you;///当前结点的左右儿子标号
     38     int c;      ///记录存在于这个区间的点的个数
     39 }tree[maxn*40];///一般乘上nlogn就够用
     40 int id,a[maxn],gen[maxn],first[maxn];
     41 ///id:每个树结点的标号
     42 ///a[]:去重后且离散化后的数组
     43 ///gen[]:树根结点的标号
     44 void build(int l,int r) {
     45     id++;
     46     tree[id].c=0;
     47     tree[id].l=l;
     48     tree[id].r=r;
     49     tree[id].zuo=tree[id].you=-1;
     50     int now=id; ///attention!!!
     51     if(l<r) {
     52         int mid=l+r>>1;
     53         tree[now].zuo=id+1;build(l,mid); ///now不要写成id
     54         tree[now].you=id+1;build(mid+1,r);
     55     }
     56 }
     57 void add(int x) {
     58     int now=gen[x-1];gen[x]=id+1;
     59     do {
     60         int zuo=tree[now].zuo,you=tree[now].you;
     61         ///zuo:now的左儿子标号,you同理
     62         id++;
     63         tree[id].c=tree[now].c+1;///插入一个数,比上一次多1
     64         tree[id].l=tree[now].l;
     65         tree[id].r=tree[now].r;
     66         if(zuo==-1) {///当前是叶子结点
     67             tree[id].zuo=tree[id].you=-1;
     68             break;
     69         }
     70         if(a[x]<=tree[zuo].r) { ///大小在左子树范围内
     71             tree[id].zuo=id+1;
     72             tree[id].you=you;///沿用上一棵树的右子树
     73             now=zuo;///递归左子树
     74         }
     75         else {  ///同理
     76             tree[id].zuo=zuo;///沿用上一棵树的左子树
     77             tree[id].you=id+1;
     78             now=you;///递归右子树
     79         }
     80     }while(now!=-1);
     81 }
     82 int found(int x,int y,int k) {
     83     int l=gen[x-1],r=gen[y];
     84     while(tree[r].zuo!=-1) {///一直判到叶子结点
     85         int zuo_sum=tree[tree[r].zuo].c-tree[tree[l].zuo].c;
     86         int you_sum=tree[tree[r].you].c-tree[tree[l].you].c;
     87         ///统计左右结点的数的个数
     88         if(k<=zuo_sum) {///如果在左儿子里,就往左儿子走
     89             l=tree[l].zuo;
     90             r=tree[r].zuo;
     91         }
     92         else {  ///如果在右儿子里,就往右儿子走
     93             l=tree[l].you;
     94             r=tree[r].you;
     95             k-=zuo_sum; ///attention!!!
     96         }
     97     }
     98     return tree[r].l;
     99 }
    100 int main()
    101 {
    102     int n,m;
    103     read(n),read(m);///n个树,m个询问
    104     for(int i=1;i<=n;i++)    ///读入n个数
    105         read(b[i].x),b[i].pos=i;
    106     sort(b+1,b+1+n);
    107     int cnt=0;
    108     for(int i=1;i<=n;i++) { ///下面进行去重
    109         if(i==1||b[i].x!=b[i-1].x) a[b[i].pos]=++cnt;///直接在a数组上修改
    110         else a[b[i].pos]=cnt;
    111         first[cnt]=b[i].x;  ///记录这个序号对应的x
    112     }
    113     build(1,n); ///建树
    114     gen[0]=1;   ///由上一步得知,第一棵树的根标号是1
    115     for(int i=1;i<=n;i++)///插入结点(建立剩下的n棵树)
    116         add(i);
    117     for(int i=1;i<=m;i++) {
    118         int l,r,k;
    119         read(l);read(r);read(k);
    120         write(first[found(l,r,k)]);pn;
    121     }
    122     return 0;
    123 }
    View Code
  • 相关阅读:
    timer使用方法
    基于开源库jsoncpp的json字符串解析
    jsoncpp构造json字符串和json数组
    通过wifi连接android设备的方法
    Linux 利用管道父子进程间传递数据
    Mac OS X 下部分Android手机无法连接adb问题之解决方案
    android studio 慢的问题
    forever让nodejs后台运行
    js里面如何才能让成员方法去调用类中其他成员
    让Windows Server 2008 + IIS 7+ ASP.NET 支持10万并发请求
  • 原文地址:https://www.cnblogs.com/wuliking/p/11746374.html
Copyright © 2020-2023  润新知