• 主席树(可持久化权值线段树)入门学习笔记


    前置知识:可持久化线段树权值线段树

    参考大佬博客:「黑历史」浅谈权值线段树到主席树   (想直接看主席树的话就跳到中间部分开始看)

     总述:

      (以求区间第k小为例)值域线段树维护一个单调递增的值域的数的出现次数。主席树将原序列的下标看做时间戳,这里还应用了前缀和、前缀可减性的思想。把求原序列区间[l,r]上的答案(这里为第k小的数)的问题,转化为将第r个版本与第l-1个版本的可持久化值域线段树相减后得到新树,再从新树上求全局答案的问题。但实际操作中并不用真的做一次线段树合并(相减),只需在这两棵线段树上从根开始同时走,记第r个版本与第l-1个版本的线段树当前节点的键值(这里为当前节点代表值域中的数的出现次数)分别为v、u,只需将k与u-v相比后 得出答案/递归就好(若向右递归,别忘k-=u-v)。

    模板题:【模板】可持久化线段树 2(主席树)

      题解口胡:

        先离散化。然后按总述说的做。

    ac代码:

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<algorithm>
      4 
      5 #define qiumid (l+r>>1)
      6 
      7 using namespace std;
      8 
      9 const int N=2e5+5;
     10 
     11 int n,tre[N*23],cnt,hed[N],lson[N*23],rson[N*23],m,nn;
     12 int dic[N];
     13 
     14 struct node{
     15     int num,ord,def;
     16 }ai[N];
     17 
     18 inline int read()//N
     19 {
     20     int x=0;
     21     bool f=0;
     22     char ch=getchar();
     23     while(!isdigit(ch))
     24         f|=ch=='-',ch=getchar();
     25     while(isdigit(ch))
     26         x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
     27     return f?-x:x;
     28 }
     29 
     30 inline bool cmp1(const node &a,const node &b)
     31 {
     32     return a.num<b.num;
     33 }
     34 
     35 inline bool cmp2(const node &a,const node &b)
     36 {
     37     return a.ord<b.ord;
     38 }
     39 
     40 void build(int t,int l,int r)
     41 {
     42     if(l==r)
     43         return;
     44     int mid=qiumid;
     45     lson[t]=++cnt;
     46     build(cnt,l,mid);
     47     rson[t]=++cnt;
     48     build(cnt,mid+1,r);
     49 }
     50 
     51 void insert(int u,int t,int l,int r,int w)
     52 {
     53     if(l==r)
     54     {
     55         tre[u]=tre[t]+1;
     56         return;
     57     }
     58     int mid=qiumid;
     59     if(w<=mid)
     60     {
     61         rson[u]=rson[t];
     62         lson[u]=++cnt;
     63         insert(cnt,lson[t],l,mid,w);
     64     }
     65     else
     66     {
     67         lson[u]=lson[t];
     68         rson[u]=++cnt;
     69         insert(cnt,rson[t],mid+1,r,w);
     70     }
     71     tre[u]=tre[lson[u]]+tre[rson[u]];
     72 }
     73 
     74 int fin(int u,int v,int l,int r,int k)
     75 {
     76     if(l==r)
     77         return l;
     78     int kk;
     79     if((kk=tre[lson[v]]-tre[lson[u]])>=k)
     80         return fin(lson[u],lson[v],l,qiumid,k);
     81     else
     82         return fin(rson[u],rson[v],qiumid+1,r,k-kk);
     83 }
     84 
     85 int main()
     86 {
     87 //  freopen(".in","r",stdin);
     88 //  freopen(".out","w",stdout);
     89     n=read();m=read();
     90     for(int i=1;i<=n;++i)
     91     {
     92         ai[i].num=read();
     93         ai[i].ord=i;
     94     }
     95     sort(ai+1,ai+1+n,cmp1);
     96     ai[1].def=nn=1;
     97     dic[1]=ai[1].num;
     98     for(int i=2;i<=n;++i)
     99     {
    100         if(ai[i].num==ai[i-1].num)
    101             ai[i].def=nn;
    102         else
    103         {
    104             ai[i].def=++nn;
    105             dic[nn]=ai[i].num;
    106         }
    107     }
    108     sort(ai+1,ai+1+n,cmp2);
    109     hed[0]=cnt=1;
    110     build(1,1,nn);
    111     for(int i=1;i<=n;++i)
    112     {
    113         hed[i]=++cnt;
    114         insert(cnt,hed[i-1],1,nn,ai[i].def);
    115     }
    116     int ll,rr,k;
    117     for(int i=1;i<=m;++i)
    118     {
    119         ll=read(),rr=read(),k=read();
    120         printf("%d
    ",dic[fin(hed[ll-1],hed[rr],1,nn,k)]);
    121     }
    122     return 0;
    123 }

    应用:

      静态区间(即无修改,有修改请去隔壁树套树)第k大

       

  • 相关阅读:
    linux下配置redis
    前端之JavaScript:JS之DOM对象一
    前端之JavaScript:JavaScript对象
    css样式之补充
    css属性中常见的操作方法
    css属性操作
    css选择器
    html 表单操作
    前端基础之html
    1231211221211221
  • 原文地址:https://www.cnblogs.com/InductiveSorting-QYF/p/14035050.html
Copyright © 2020-2023  润新知