• poj 2104 可持久化线段树


      我们先离散化,然后根据权值建立线段树,假设我们现在有一颗权值线段树,表示在区间1-n中每个数出现了几次,那么我们可以二分的求出来这个区间的k大值,类似sbt的select操作,那么因为点的权值插入是无序的,所以我们并不能对于子区间l,r做上述操作,因为我们无法提出这个区间,那么我们建立可持久化线段树就好了。

      反思:第一次写可持久化数据结构,自己yy着写的,开始没注意到新建节点的时候节点的值就应该是上一棵线段树中该节点对应节点的值+1,而是维护的这个值,就导致了各种重复计算问题= =。

      

    //By BLADEVIL
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define maxn 100010
    
    using namespace std;
    
    struct segment {
        int left,right,sum;
        int son[2];
        segment(){
            left=right=sum=0;
            memset(son,0,sizeof son);
        }
    }t[maxn<<5];
    
    struct rec {
        int num,key;
    }a[maxn];
    
    int n,m,tot;
    int rot[maxn],ans[maxn];
    
    bool cmp1(rec x,rec y) {
        return x.key<y.key;
    }
    
    bool cmp2(rec x,rec y) {
        return x.num<y.num;
    }
    
    void build(int &x,int l,int r) {
        if (!x) x=++tot;
        t[x].left=l; t[x].right=r;
        if (l==r) return ;
        int mid=t[x].left+t[x].right>>1;
        build(t[x].son[0],l,mid); build(t[x].son[1],mid+1,r);
    }
    
    void insert(int &x,int rot,int y,int l,int r) {
        if (!x) x=++tot;
        t[x].left=l; t[x].right=r;
        if (l==r) {
            t[x].sum=t[rot].sum+1; return ;
        }
        int mid=t[x].left+t[x].right>>1;
        if (y>mid) {
            insert(t[x].son[1],t[rot].son[1],y,mid+1,r);
            t[x].son[0]=t[rot].son[0];
            //t[t[x].son[0]].sum=t[t[t[x].son[0]].son[0]].sum+t[t[t[x].son[0]].son[1]].sum;
        } else {
            insert(t[x].son[0],t[rot].son[0],y,l,mid);
            t[x].son[1]=t[rot].son[1];
            //t[t[x].son[1]].sum=t[t[t[x].son[1]].son[0]].sum+t[t[t[x].son[1]].son[1]].sum;
        }
        t[x].sum=t[rot].sum+1;
    }
    
    int ask(int lx,int rx,int k) {
        //printf("|%d %d %d
    ",lx,rx,k);
        if (t[lx].left==t[lx].right) return t[lx].left;
        if (k>t[t[rx].son[0]].sum-t[t[lx].son[0]].sum) 
            return ask(t[lx].son[1],t[rx].son[1],k-t[t[rx].son[0]].sum+t[t[lx].son[0]].sum); else 
            return ask(t[lx].son[0],t[rx].son[0],k);
    }
    
    int main() {
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++) scanf("%d",&a[i].key),a[i].num=i;
        sort(a+1,a+1+n,cmp1);
        int j=1; ans[1]=a[1].key;
        for (int i=1,cur=a[1].key;i<=n;i++)
            if (a[i].key==cur) a[i].key=j; else cur=a[i].key,a[i].key=++j,ans[j]=cur;
        //for (int i=1;i<=n;i++) printf("%d %d
    ",a[i].num,a[i].key);
        sort(a+1,a+1+n,cmp2);
        build(rot[0],1,j);
        for (int i=1;i<=n;i++) insert(rot[i],rot[i-1],a[i].key,1,j);
        //for (int i=1;i<=tot;i++) printf("%d %d %d %d %d %d
    ",i,t[i].son[0],t[i].son[1],t[i].left,t[i].right,t[i].sum);
        for (int i=1;i<=m;i++) {
            int l,r,k; scanf("%d%d%d",&l,&r,&k);
            printf("%d
    ",ans[ask(rot[l-1],rot[r],k)]);
        }
        //for (int i=1;i<=j;i++) printf("%d ",ans[i]); printf("
    ");
        //for (int i=1;i<=n;i++) printf("%d ",a[i].key); printf("
    ");
        return 0;
    }
  • 相关阅读:
    ISBN号码
    计数问题
    小玉在游泳
    数字反转
    单调队列(学习笔记)
    LCA(学习笔记)
    emacs配置文件
    线段树(学习笔记)
    RMQ问题 ST算法(学习笔记)
    Lucas卢卡斯定理(学习笔记)
  • 原文地址:https://www.cnblogs.com/BLADEVIL/p/3667813.html
Copyright © 2020-2023  润新知