poj2104 K-th Number 主席树入门;

题目链接:K-th Number

题解:我们先把数组离散离散化一下,然后先不考虑L,R的区间的关系,我们有一个棵线段树sum[]保存的是第几大到第几大出现的个数,这样我们想要询问这颗线段数的第k大是多少可以在log(n)次下就找到,但是区间的不同,一颗线段树是解决不了的,那我们如何得到L,R区间的sum数组呢?。我们可以建N棵线段树,第一棵树是空树,然后第一个数过来我们再建一课线段树在原来树的基础上,加上这个数对sum数组的贡献,这样从第一个到第N个建N棵线段树建好,我们可以发现sum【】有前缀和的性质,这样我们通过第R棵树sum[]减去L-1棵树的sum[],这样我就可以得到L,R区间的sum【】数组。然后就可以查询第K大了,。现在最关建如何建N棵线段树(这是主席树的关建所在)。直接建N棵线段树空间复杂度会直接爆炸我们可以发现,对于第i+1棵树与第i棵数相比它只会更改不超过log(N)个结点,其他结点都是相同。所以在建第i+1棵树时就可以只要重新花费log(N)节点保存新的sum[]。让后用一个root[]保存每棵树的根节点。这么一说还不太理解的可以对着代码看看。

//#include<bits/stdc++.h>
#include<set>
#include<cstdio>
#include<iomanip>
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#define pb push_back
#define ll long long
#define PI 3.14159265
//#define ls l,m,rt<<1
//#define rs m+1,r,rt<<1|1
#define eps 1e-7
typedef unsigned long long ull;
const int mod=1e9+9;
const ll inf=0x3f3f3f3f3f3f3f;
const int maxn=1e5+5;
using namespace std;
int a[maxn],b[maxn],tr[maxn*20],ls[maxn*20],rs[maxn*20],sum[20*maxn],rt[maxn],t,s,n,m,tot;
void built(int &o,int l,int r)
{
    o=++tot;
    int m=(l+r)>>1;
    if(l==r)return ;
    sum[o]=0;
    built(ls[o],l,m);
    built(rs[o],m+1,r);
}
void update(int &o,int pre,int l,int r,int x)
{
    o=++tot;
    ls[o]=ls[pre];rs[o]=rs[pre];
    int m=(l+r)>>1;
    sum[o]=sum[pre]+1;
    //cout<<sum[o]<<endl;
    if(l==r)return;
    if(x<=m) update(ls[o],ls[pre],l,m,x);
    else update(rs[o],rs[pre],m+1,r,x);
}
int query(int r1,int r2,int l,int r,int k)
{
    if(l==r)
    {
        return l;
    }
    int m=(l+r)>>1;
    int cn=sum[ls[r1]]-sum[ls[r2]];
   // cout<<ls[r1]<<"*"<<ls[r2]<<" "<<l<<‘ ‘<<r<<‘ ‘<<cn<<endl;
    if(cn>=k)
    {
        return query(ls[r1],ls[r2],l,m,k);
    }
    else
    {
        return query(rs[r1],rs[r2],m+1,r,k-cn);
    }
}
int main()
{
   // scanf("%d",&t);
  //  while(t--)
   // {
        scanf("%d %d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]),b[i]=a[i];
        sort(b+1,b+n+1);
        int sz=unique(b+1,b+1+n)-b-1;
        tot=0;
        built(rt[0],1,sz);
        for(int i=1;i<=n;i++)
        {
            a[i]=lower_bound(b+1,b+sz,a[i])-b;
        }
        for(int i=1;i<=n;i++)
        {
            update(rt[i],rt[i-1],1,sz,a[i]);
        }
        while(m--)
        {
            int x,y,z;
            scanf("%d %d %d",&x,&y,&z);
            int id=query(rt[y],rt[x-1],1,sz,z);
            printf("%d\n",b[id]);
        }
   // }
    return 0;
}

原文地址:https://www.cnblogs.com/lhclqslove/p/8673200.html

时间: 2025-02-01 00:58:29

poj2104 K-th Number 主席树入门;的相关文章

poj2104求区间第k小,静态主席树入门模板

看了很久的主席树,最后看https://blog.csdn.net/williamsun0122/article/details/77871278这篇终于看懂了 #include <stdio.h> #include<algorithm> using namespace std; typedef long long ll; const int maxn = 1e5+5; int T[maxn],L[maxn*20],R[maxn*20],sum[maxn*20]; //sz[]为原

【POJ2104】K-th Number——主席树

早上刷NOIP的题刷到有点烦就想学点新东西,然后.....一个早上就这样过去了QAQ.虽然主席树不是NOIP考点,但是...或许我能活到省选呢?(美好的幻想) 题目链接 题目的大意就是给定一个长度为n的区间,给出m个询问,每次询问一个区间[l,r]中第k小的树. 主席树(一种可持久化线段树)的入门题. 推荐一发学习资料:戳这里 感觉人家讲得很仔细了我也没什么讲的必要了...... 总算是学了一种可持久化树了,好像也没想象中那么难?这道题的重点在query函数方面,建议自己在纸上模拟一下建树和查询

【POJ2104】K-th Number 主席树?函数式线段树?可持久化线段树?……反正是其中一个

题意:区间静态第K大. 题解: 可持久化线段树. 可持久化线段树: 基本思想:我们维护插入每个节点后的线段树. 朴素写法(MLE+TLE)我们对于每次插入,都复制一棵线段树而后插入,这样保证了"可持久化". 但是显然,时间复杂度和空间复杂度都是n^2的.233. 所以有了优化写法:我们发现每次的插入只有logn个节点被改变,所以只需要这些点新建,其它点都指向原来版本的节点就好了. 空间复杂度nlogn. 然后这道题是区间第K大,对于区间[a,b],插入到b时的线段树,节点的size-(

Poj 2104(主席树入门

题目:静态查询区间第k大. 主席树入门题目,之前看的很多资料一上来就是动态区间第k大,看得很费劲,后来找了个写得清晰的,感觉静态的还不算难,代码也不长. /* * @author: Cwind */ //#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cs

AcWing 255. 第K小数 (主席树写法)

区间k小数是主席树的模板题目,如果区间不包含,用莫队+权值线段树也能解 主席树是可持久化线段树,所为可持久化,就是每次只新增不一样的节点,而保留前面的版本,这样可以做到查询. 如果询问时1-r,那么直接主席树,询问的是l-r,就用到前缀和思想,具体看代码注释 #include<iostream> #include<algorithm> #include<cstdio> #include<cmath> #include<vector> #inclu

POJ2104 K-th Number[主席树]

K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 51440   Accepted: 17594 Case Time Limit: 2000MS Description You are working for Macrohard company in data structures department. After failing your previous task about key inse

POJ 2104&amp;HDU 2665 Kth number(主席树入门+离散化)

K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 50247   Accepted: 17101 Case Time Limit: 2000MS Description You are working for Macrohard company in data structures department. After failing your previous task about key inse

[知识点]主席树入门 区间k值

入坑主席树主要是因为昨天考试的后两道题不可改2333 而且觉得这个还挺有用,于是果断入坑 不过蒟蒻的我只是在上午看了看大概思路,下午开的运动会没时间码,于是晚上码了出来.但是目前只会无修改的区间K值问题,加上又比较抽象,思路屡了半天才刚刚醒悟,于是写下来记录一下. 不扯那么多辣鸡套路,直接说思路打法(以k小值为例): 我们先要以权值建一颗线段树,然后每个节点记录的是这个节点管辖的范围内数列中数的个数. 我们需要建好多好多线段树.简单来讲呢,就是[1,1],[1,2]···[1,n]这么多颗,每棵

zoj2112 主席树动态第k大 (主席树&amp;&amp;树状数组)

Dynamic Rankings Time Limit: 10 Seconds      Memory Limit: 32768 KB The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with the query like to simply find the k-th smallest number of the given N numbers. They