• 主席树和划分树板子一


     P3834 【模板】可持久化线段树 1(主席树)

    题目背景

    这是个非常经典的主席树入门题——静态区间第K小

    数据已经过加强,请使用主席树。同时请注意常数优化

    题目描述

    如题,给定N个正整数构成的序列,将对于指定的闭区间查询其区间内的第K小值。

    输入输出格式

    输入格式:

     

    第一行包含两个正整数N、M,分别表示序列的长度和查询的个数。

    第二行包含N个正整数,表示这个序列各项的数字。

    接下来M行每行包含三个整数l, r, kl,r,k , 表示查询区间[l, r][l,r]内的第k小值。

     

    输出格式:

     

    输出包含k行,每行1个正整数,依次表示每一次查询的结果

     

    输入输出样例

    输入样例#1: 复制
    5 5
    25957 6405 15770 26287 26465 
    2 2 1
    3 4 1
    4 5 1
    1 2 2
    4 4 1
    输出样例#1: 复制
    6405
    15770
    26287
    25957
    26287
    

    说明

    数据范围:

    对于20%的数据满足:1 leq N, M leq 101N,M10

    对于50%的数据满足:1 leq N, M leq 10^31N,M103

    对于80%的数据满足:1 leq N, M leq 10^51N,M105

    对于100%的数据满足:1 leq N, M leq 2cdot 10^51N,M2105

    对于数列中的所有数a_iai,均满足-{10}^9 leq a_i leq {10}^9109ai109

    样例数据说明:

    N=5,数列长度为5,数列从第一项开始依次为[25957, 6405, 15770, 26287, 26465 ][25957,6405,15770,26287,26465]

    第一次查询为[2, 2][2,2]区间内的第一小值,即为6405

    第二次查询为[3, 4][3,4]区间内的第一小值,即为15770

    第三次查询为[4, 5][4,5]区间内的第一小值,即为26287

    第四次查询为[1, 2][1,2]区间内的第二小值,即为25957

    第五次查询为[4, 4][4,4]区间内的第一小值,即为26287

    主席树真是个好东西,比划分树不知高到哪里去.

    主席树

    #include<stdio.h>
    #include<algorithm>
    #define FOR(i,s,t) for(register int i=s;i<=t;++i)
    using std::sort;
    using std::lower_bound;
    using std::unique;
    const int NlogN=3521999;
    const int N=200011;
    int a[N],b[N];
    int n,m,len,tot;
    int l,r,k;
    int rt[N];
    inline void disc_init(){
    	sort(b+1,b+n+1);
    	len=unique(b+1,b+n+1)-b-1;
    	FOR(i,1,n)a[i]=lower_bound(b+1,b+len+1,a[i])-b;
    }
    struct Tree{
    	int ls,rs,sum;
    }tr[NlogN<<2];
    inline void insert(int &x,int &y,int l,int r,int p){
    	tr[x=++tot]=tr[y];
    	++tr[x].sum;
    	if(l==r)return;
    	int mid=(l+r)>>1;
    	p<=mid?insert(tr[x].ls,tr[y].ls,l,mid,p):insert(tr[x].rs,tr[y].rs,mid+1,r,p);
    }
    inline void build_tree(){
    	FOR(i,1,n)insert(rt[i],rt[i-1],1,len,a[i]);
    }
    inline int query(int x,int y,int l,int r,int p){
    	if(l==r)return l;
    	int mid=(l+r)>>1;
    	int data=tr[tr[x].ls].sum-tr[tr[y].ls].sum;
    	return p<=data?query(tr[x].ls,tr[y].ls,l,mid,p):query(tr[x].rs,tr[y].rs,mid+1,r,p-data);
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	FOR(i,1,n)scanf("%d",a+i),b[i]=a[i];
    	disc_init();
    	build_tree();
    	while(m--){
    		scanf("%d%d%d",&l,&r,&k);
    		printf("%d
    ",b[query(rt[r],rt[l-1],1,len,k)]);
    	}
    	return 0;
    }
    

      

    划分树

    #include<stdio.h>
    #include<algorithm>
    #define FOR(i,s,t) for(register int i=s;i<=t;++i)
    using std::sort;
    const int N=1000011;
    typedef long long LL;
    int a[N];
    int sorted[N];
    int num[21][N];
    int val[21][N];
    inline void build(int l,int r,int dep){
        if(l==r) return ;
        int mid=(l+r)>>1,isame=mid-l+1;
        FOR(i,l,r) 
            if(val[dep][i]<sorted[mid]) --isame;
        int ln=l,rn=mid+1;
        FOR(i,l,r){
            i==l?num[dep][i]=0:num[dep][i]=num[dep][i-1];
        	if(val[dep][i]<sorted[mid]||(val[dep][i]==sorted[mid]&&isame>0)){
           		val[dep+1][ln++]=val[dep][i];
          		++num[dep][i];
              	if(val[dep][i]==sorted[mid]) 
                  	--isame;
            }
            else
             	val[dep+1][rn++]=val[dep][i];
        }
        build(l,mid,dep+1);
        build(mid+1,r,dep+1);
    }
    inline int query(int dep,int sl,int sr,int l,int r,int k){
        if(sl==sr) return val[dep][sl];
        int ly;
        l==sl?ly=0:ly=num[dep][l-1];
        int tolef=num[dep][r]-ly;
        int mid=(sl+sr)>>1;
        int lr=mid+1+(l-sl-ly);
        return tolef>=k?query(dep+1,sl,mid,sl+ly,sl+num[dep][r]-1,k):query(dep+1,mid+1,sr,lr,lr+r-l-tolef,k-tolef);
    }
    int main(){
        int n,m,l,r,k;
        scanf("%d%d",&n,&m);
        FOR(i,1,n){
            scanf("%d",&val[0][i]);
            sorted[i]=val[0][i];
        }
        sort(sorted+1,sorted+n+1);
        build(1,n,0);
        while(m--){
            scanf("%d%d%d",&l,&r,&k);
            printf("%d
    ",query(0,1,n,l,r,k));
        }
        return 0;
    }
    

      

  • 相关阅读:
    eclipse恢复界面默认设置
    文件夹的拷贝
    文件的输入输出
    十进制转二进制,八进制,十六进制(查表法)
    数组元素的查找(折半查找)
    C++几个小函数
    C++ 内部排序(一)
    C++实现链表
    C++输出IP地址段内的合法地址
    我看软件工程师的职业规划
  • 原文地址:https://www.cnblogs.com/Stump/p/7856883.html
Copyright © 2020-2023  润新知