• hdu2665 主席树模板题


    题目
    http://acm.hdu.edu.cn/showproblem.php?pid=2665

    区间k大值,区间极值很容易想到线段树,如果k是个位数的话,可以考虑开k个域的线段树= =,,,,滚~
    又称可持久化线段树,函数式线段树
    也许是上面两个字看的太长,同时主席两字给人一种不明觉厉的感觉,,,so,嘿嘿嘿

    关于主席树的讲解可以看这
    http://wenku.baidu.com/link?url=6sjYgDa2UEZujFwLE4KDqgJlOs0tio-hwKMoDBexBLKT6DSgSiq4Ed-w8cHF4L3JraAflBURPdzeHeOft-f02RT1xfneYIfM5pTVs3t1cBi

    先离散化,对每个点i,建一个1~i的线段树(大小是数字的个数)
    记录该前缀序列里出现的值的次数;记离散后的标记为1~n;
    对于区间[x,y]的第k大的值,那么从root[x-1],root[y]开始,
    t=root[y].[1,mid]-root[x-1].[1,mid] ,t表示区间[x,y]内值在[1,mid]的个数
    先判断t是否大于K,如果t大于k,那么说明在区间[x,y]内存在[1,mid]的数的个数大于k,
    也就是第k大的值在[1,mid]中,否则在[mid+1,r]中;

    这样我们依次同时从root[x-1],root[y]往下走
    当l==r时 第k大的值就是离散后标记为l的值;

    如果每棵线段都建完整的化,n^2肯定会mle,,,BANG!!!
    我们发现对于前缀[1,i]和前缀[1,i+1]的线段树,如果b[i+1]<=mid (b[i+1]表示a[i+1]离散后的标记)
    那么线段树i和线段树i+1的左边是完全相同的,根本不需要在建,直接链过去就好;
    那么对于一棵新的线段树其实我们最多要建的节点数为log(n);nlog(n)的节点数,duangduangduang

    存个代码吧,,,,以后如果写熟练了有空写个去重的离散

    //嘿嘿嘿
    # include <cstdio>
    # include <iostream>
    # include <algorithm>
    # define N 100100
    using namespace std;
    int i,n,m,root[N],a[N],p[N],b[N],cnt;
    struct node{int lc,rc,w;}T[N*30];
    bool cmp(int i,int j){return a[i]<a[j];}
    
    void build(int &rot,int l,int r,int x){
        T[++cnt]=T[rot];rot=cnt;
        T[cnt].w++;
        if (l==r)return ;
        int mid=(l+r) >> 1;
        if (x<=mid)build(T[cnt].lc,l,mid,x);
        else build(T[cnt].rc,mid+1,r,x);
    }
    
    int query(int x,int y,int l,int r,int k){
        if (l==r)return l;
        int t=T[T[y].lc].w-T[T[x].lc].w;
        int mid=(l+r) >> 1;
        if (t>=k)return query(T[x].lc,T[y].lc,l,mid,k);
        else return query(T[x].rc,T[y].rc,mid+1,r,k-t);
    }
    
    int main(){
        //freopen("fuck.in","r",stdin);
        int cas;scanf("%d",&cas);
        for (;cas--;){
            root[0]=0;cnt=0;
            scanf("%d%d",&n,&m);
            for (int i=1;i<=n;i++)
              {scanf("%d",&a[i]);p[i]=i;}
            sort(p+1,p+n+1,cmp);
            for (int i=1;i<=n;i++)b[p[i]]=i;
            for (int i=1;i<=n;i++){
                root[i]=root[i-1];
                build(root[i],1,n,b[i]);
            }
            for (int i=1;i<=m;i++){
                int x,y,k; scanf("%d%d%d",&x,&y,&k);
                int t=query(root[x-1],root[y],1,n,k);
                printf("%d
    ",a[p[t]]);
            }
        }
        return 0;
    } 
  • 相关阅读:
    css 设置特定宽度,超出部分用...代替
    php 二维数组根据某个key去重
    一些大厂开源项目
    JavaScript如何解析本地xml文件
    console的知识点
    toLocalDateString的用途
    在Vue中使用Object.freeze
    淘宝npm镜像
    JavaScript Async/Await
    vue中的addEventListener和removeEventListener
  • 原文地址:https://www.cnblogs.com/cww97/p/12349445.html
Copyright © 2020-2023  润新知