[poj 2104]主席树+静态区间第k大

题目链接:http://poj.org/problem?id=2104

主席树入门题目,主席树其实就是可持久化权值线段树,rt[i]维护了前i个数中第i大(小)的数出现次数的信息,通过查询两棵树的差即可得到第k大(小)元素。

#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;

#define lson(i) node[i].lson
#define rson(i) node[i].rson

const int maxn=100005;
int rt[maxn];

struct Node
{
    int lson,rson,val;
}node[maxn*30];
int tot;

void push_up(int i)
{
    node[i].val=node[lson(i)].val+node[rson(i)].val;
}

int build(int l,int r)
{
    int i=++tot;
    if (l==r) node[i].val=0;
    else
    {
        int mid=(l+r)/2;
        lson(i)=build(l,mid);
        rson(i)=build(mid+1,r);
        push_up(i);
    }
    return i;
}

int rebuild(int k,int x,int i,int nowl,int nowr)
{
    int th=++tot;
    lson(th)=lson(i);
    rson(th)=rson(i);
    node[th].val=node[i].val;
    if (nowl==nowr) node[th].val+=x;
    else
    {
        int mid=(nowl+nowr)/2;
        if (k<=mid) node[th].lson=rebuild(k,x,lson(i),nowl,mid);
        else node[th].rson=rebuild(k,x,rson(i),mid+1,nowr);
        push_up(th);
    }
    return th;
}

int query(int rt1,int rt2,int k,int nowl,int nowr)
{
    if (nowl==nowr) return nowl;
    int left=node[lson(rt2)].val-node[lson(rt1)].val;
    int mid=(nowl+nowr)/2;
    if (left>=k) return query(lson(rt1),lson(rt2),k,nowl,mid);
    else return query(rson(rt1),rson(rt2),k-left,mid+1,nowr);
}

int a[maxn];
vector<int> ls;

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    ls.clear();
    for (int i=1;i<=n;i++) ls.push_back(a[i]);
    sort(ls.begin(),ls.end());
    ls.erase(unique(ls.begin(),ls.end()),ls.end());
    rt[0]=build(1,n);
    for (int i=1;i<=n;i++)
    {
        int j=lower_bound(ls.begin(),ls.end(),a[i])-ls.begin();
        rt[i]=rebuild(j+1,1,rt[i-1],1,n);
    }
    for (int i=1;i<=m;i++)
    {
        int l,r,k;
        scanf("%d%d%d",&l,&r,&k);
        printf("%d\n",ls[query(rt[l-1],rt[r],k,1,n)-1]);
    }
    return 0;
}
时间: 2024-10-04 08:31:49

[poj 2104]主席树+静态区间第k大的相关文章

poj 2104主席树求区间第k小

POJ - 2104 题意:求区间第k小 思路:无修改主席树 AC代码: #include "iostream" #include "iomanip" #include "string.h" #include "stack" #include "queue" #include "string" #include "vector" #include "set&

POJ2104-- K-th Number(主席树静态区间第k大)

[转载]一篇还算可以的文章,关于可持久化线段树http://finaltheory.info/?p=249 无修改的区间第K大 我们先考虑简化的问题:我们要询问整个区间内的第K大.这样我们对值域建线段树,每个节点记录这个区间所包含的元素个数,建树和查询时的区间范围用递归参数传递,然后用二叉查找树的询问方式即可:即如果左边元素个数sum>=K,递归查找左子树第K大,否则递归查找右子树第K – sum大,直到返回叶子的值. 现在我们要回答对于区间[l, r]的第K大询问.如果我们能够得到一个插入原序

HDU3727--Jewel (主席树 静态区间第k大)

Jewel Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 985    Accepted Submission(s): 247 Problem Description Jimmy wants to make a special necklace for his girlfriend. He bought many beads with

poj 2401 划分树 求区间第k大的数

题目:http://poj.org/problem?id=2104 划分树待我好好理解下再写个教程吧,觉得网上的内容一般,,, 模板题: 贴代码: #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define CLR(a) memset(a,0,sizeof(a)) const int MAXN = 1000

洛谷.3834.[模板]可持久化线段树(主席树 静态区间第k小)

题目链接 //离散化后范围1~cnt不要错 #include<cstdio> #include<cctype> #include<algorithm> //#define gc() getchar() #define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++) const int N=2e5+5,MAXIN=2e6; int n,m,A[N],ref[N],cn

poj2761静态区间第k大

例题:poj2761 题目要求:给定一个长度为n的序列,给定m个询问,每次询问求[l,r]区间内的第k大: 对于这道题目来说,很多算法都可以使用,比如说树套树(一个负责划分区间,一个负责维护这段区间内的信息),主席树等: 对这道题我使用的是主席树: 主席树对付区间第k大是很优秀的,代码短,而且常数小: 主席树的主要功能是,建立n颗范围是1-i的权值线段树,对两颗线段树做差,就可以任意一个区间内的权值线段树: 详细看代码: #include<iostream> #include<cstdi

主席树(静态区间第k大)

前言 如果要求一些数中的第k大值,怎么做? 可以先就这些数离散化,用线段树记录每个数字出现了多少次. ... 那么考虑用类似的方法来求静态区间第k大. 原理 假设现在要有一些数 我们可以对于每个数都建一棵新的线段树,用来记录出现每个数字出现了多少次的前缀和. 那么假设要求区间[l,r]的第k大,将第r棵线段树减去第l-1棵线段树,像上面求所有数的第k大一样来求就可以了. 但是,对于每一个数都建一个线段树显然会爆空间. 现在考虑如何节约空间. 假设现在有四个数1 4 2 3,依次加入,可以这样处理

hdu 2665 可持久化线段树求区间第K大值(函数式线段树||主席树)

http://acm.hdu.edu.cn/showproblem.php?pid=2665 Problem Description Give you a sequence and ask you the kth big number of a inteval. Input The first line is the number of the test cases. For each test case, the first line contain two integer n and m (

HDU 5919 - Sequence II (2016CCPC长春) 主席树 (区间第K小+区间不同值个数)

HDU 5919 题意: 动态处理一个序列的区间问题,对于一个给定序列,每次输入区间的左端点和右端点,输出这个区间中:每个数字第一次出现的位子留下, 输出这些位子中最中间的那个,就是(len+1)/2那个. 思路: 主席树操作,这里的思路是从n到1开始建树.其他就是主席树查询区间第K小,计算区间不同值个数. #include <algorithm> #include <iterator> #include <iostream> #include <cstring&