• 静态区间第K小 (主席树模板 洛谷3834 )


    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int maxn=2e5+10;
    
    struct Tree{
        int l,r,s;
    }tree[maxn*32];//开32倍
    
    struct node{
        int w,pos;
    }a[maxn];
    
    int b[maxn],c[maxn],root[maxn];
    //b 离散后的位置 c原值 root个树的根
    
    int k=0,tot=0;
    
    void dc(int n)//离散化
    {
        b[a[1].pos]=++tot;
        c[tot]=a[1].w;
        for(int i=2;i<=n;i++)
        {
            if(a[i].w!=a[i-1].w)
                tot++;
            b[a[i].pos]=tot;
            c[tot]=a[i].w;
        }
    }
    
    int cmp(node a,node b)
    {
        return a.w<b.w;
    }
    
    int built(int l,int r)//建树 防止爆内存 静态分配空间
    {
        int now=++k;
        int mid=(l+r)>>1;
        if(l<r)
        {
            tree[now].l=built(l,mid);
            tree[now].r=built(mid+1,r);
        }
        return now;
    }
    
    int updata(int pre,int x,int l,int r)//更新
    {
        int mid=(l+r)>>1;
        int now=++k;
        tree[now].s=tree[pre].s+1;//区间内的数的出现次数++
        
        tree[now].l=tree[pre].l;//将左右节点先指向原树
        tree[now].r=tree[pre].r;
        if(l<r)//新建树链
        {
            if(x<=mid)
                tree[now].l=updata(tree[pre].l,x,l,mid);
            else
                tree[now].r=updata(tree[pre].r,x,mid+1,r);
        }
        return now;
    }
    
    int query(int u,int v,int x,int l,int r)//查询
    {
        int mid=(l+r)>>1;//找到第k小值 
        if(l==r) return l;
        //第r棵线段树左儿子-第(l-1)棵线段树左儿子的值 
        int t=tree[tree[v].l].s-tree[tree[u].l].s;
        //cout<<t<<endl;
    
        return x<=t?query(tree[u].l,tree[v].l,x,l,mid):query(tree[u].r,tree[v].r,x-t,mid+1,r);
    }
    
    int main()
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i].w);
            a[i].pos=i;
        }
        sort(a+1,a+1+n,cmp);
        dc(n);
    
    //    for(int i=1;i<=n;i++)
    //        cout<<a[i].w<<" ";cout<<endl;
    //    for(int i=1;i<=n;i++)
    //        cout<<b[i]<<" ";cout<<endl;
    //    for(int i=1;i<=n;i++)
    //        cout<<c[i]<<" ";cout<<endl;
    
    
        root[0]=built(1,tot);
    
        for(int i=1;i<=n;i++)//建n棵线段树,边加点边建树 
            root[i]=updata(root[i-1],b[i],1,tot);
        for(int i=1;i<=m;i++)
        {
            int l,r,x;
            scanf("%d%d%d",&l,&r,&x);
    
    
           // cout<<query(l-1,r,x,1,tot)<<endl;
           //[l,r]就等价于 第r棵线段树-第(l-1)棵线段树 的k小值,返回该节点映射的值 
            printf("%d
    ",c[query(root[l-1],root[r],x,1,tot)]);
        }
        return 0;
    }
  • 相关阅读:
    R语言介绍与安装
    待分析数据数值化
    网络环路与攻击和谷歌的四个8
    基于storm和hadoop的广告系统研究【5】
    Xpath语法
    Xcode编译工具
    关于Xcode的Other Linker Flags
    iOS项目的目录结构和开发流程
    Objective-C中关于NSArray, NSDictionary, NSNumber等写法的进化
    Windows 8 常见教程
  • 原文地址:https://www.cnblogs.com/minun/p/10877995.html
Copyright © 2020-2023  润新知