• 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;
    }
  • 相关阅读:
    2、从0开始学算法 时间/空间复杂度(如何知道你的代码性能如何?)
    1、从0开始学算法 概述
    机器学习(五):通俗易懂决策树与随机森林及代码实践
    机器学习(四):通俗理解支持向量机SVM及代码实践
    机器学习(三):理解逻辑回归及二分类、多分类代码实践
    HDU 2492 Ping pong (树状数组)
    yum更新失败
    webpack3配置rules的问题
    置顶帖汇总
    2021.07.03软件更新公告
  • 原文地址:https://www.cnblogs.com/BLADEVIL/p/3667813.html
Copyright © 2020-2023  润新知