静态区间第k大 树套树解法

然而过不去你谷的模板

思路:

值域线段树\([l,r]\)代表一棵值域在\([l,r]\)范围内的点构成的一颗平衡树

平衡树的\(BST\)权值为点在序列中的位置

查询区间第\(k\)大值时

左区间在\([l,r]\)范围内的树的大小与\(k\)比较

大了进去,小了减掉换一边

关于建树

递归建估计是\(O(nlog^2n)\)的



Code:

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <vector>
const int N=1e5+10;
int ch[N*20][2],val[N*20],siz[N*20],pos[N*20],root[N<<2],tot;
#define ls ch[now][0]
#define rs ch[now][1]
int n,m,n_,a[N],b[N];
void updata(int now){siz[now]=siz[ls]+siz[rs]+1;}
void split(int now,int k,int &x,int &y)
{
    if(!now) {x=y=0;return;}
    if(pos[now]<=k)
        x=now,split(rs,k,rs,y);
    else
        y=now,split(ls,k,x,ls);
    updata(now);
}
int Merge(int x,int y)
{
    if(!x||!y) return x+y;
    if(val[x]<val[y])
    {
        ch[x][1]=Merge(ch[x][1],y);
        updata(x);
        return x;
    }
    else
    {
        ch[y][0]=Merge(x,ch[y][0]);
        updata(y);
        return y;
    }
}
int New(int k)
{
    val[++tot]=rand(),pos[tot]=k,siz[tot]=1;
    return tot;
}
void Insert(int id,int k)
{
    int x,y;
    split(root[id],k,x,y);
    root[id]=Merge(x,Merge(New(k),y));
}
int ask(int id,int l,int r)//询问区间
{
    int x,y,z,s;
    split(root[id],r,x,y);
    split(x,l-1,x,z);
    s=siz[z];
    root[id]=Merge(x,Merge(z,y));
    return s;
}
std::vector <int> loc[N];
void build(int id,int l,int r)
{
    if(l==r)
    {
        for(int i=0;i<loc[l].size();i++)
            Insert(id,loc[l][i]);
        return;
    }
    int mid=l+r>>1;
    build(id<<1,l,mid);
    build(id<<1|1,mid+1,r);
    for(int i=l;i<=r;i++)
        for(int j=0;j<loc[i].size();j++)
            Insert(id,loc[i][j]);
}
int query(int id,int l,int r,int ql,int qr,int k)
{
    if(l==r) return a[l];
    int mid=l+r>>1,cnt;
    if((cnt=ask(id<<1,ql,qr))>=k)
        return query(id<<1,l,mid,ql,qr,k);
    else
        return query(id<<1|1,mid+1,r,ql,qr,k-cnt);
}
void init()
{
    scanf("%d%d",&n_,&m);
    for(int i=1;i<=n_;i++) scanf("%d",a+i),b[i]=a[i];
    std::sort(a+1,a+1+n_);
    n=std::unique(a+1,a+1+n_)-a-1;
    for(int i=1;i<=n_;i++)
        loc[std::lower_bound(a+1,a+1+n,b[i])-a].push_back(i);
    build(1,1,n);
}
void work()
{
    for(int l,r,k,i=1;i<=m;i++)
    {
        scanf("%d%d%d",&l,&r,&k);
        printf("%d\n",query(1,1,n,l,r,k));
    }
}
int main()
{
    init(),work();
    return 0;
}


2018.9.2

原文地址:https://www.cnblogs.com/ppprseter/p/9575675.html

时间: 2024-10-13 12:19:08

静态区间第k大 树套树解法的相关文章

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

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

Poj 2104区间第k大(归并树)

题目链接 K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 36890 Accepted: 11860 Case Time Limit: 2000MS Description You are working for Macrohard company in data structures department. After failing your previous task about key ins

HDU3473--Minimum Sum(静态区间第k大)

Minimum Sum Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 3047    Accepted Submission(s): 701 Problem Description You are given N positive integers, denoted as x0, x1 ... xN-1. Then give you

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

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

zoj 2112 Dynamic Rankings 带修改区间第K大 动态主席树

pass 首先,个人觉得把这个数据结构理解成树状数组套主席树是十分不严谨的.主席树的本质是可持久化权值线段树与前缀和思想的结合.而动态主席树是可持久化权值线段树与树状数组思想的结合.并非树套树般的泾渭分明的叠加. 其次,大概讲下对动态主席树的理解.我们静态主席树中,第i个版本维护的是[1,i]的权值线段树,我们利用前缀和的思想,通过y的版本-x的版本得到[x,y]的权值线段树,从而剥离出一颗对应区间的权值线段树.我们考虑在这个情况下,如果需要修改第a[i]的值,那么从i,i+1,i+2.....

POJ 2014.K-th Number 区间第k大 (归并树)

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

poj2761静态区间第k大

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

[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

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