区间第k大数

思路是分块,不然得树套树(我是蒟蒻不会)

用分块T2的思路+二分就能求出区间第k大数

代码还未交过,先放这里

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
using namespace std;
vector<int>vec[1004];
int n,blo,v[30005],m,bl[30005],lazy[1004];
void reset(int x)
{
    vec[x].clear();

    for(int i=(x-1)*blo+1;i<=min(x*blo,n);i++)
    vec[x].push_back(v[i]);
    sort(vec[x].begin(),vec[x].end());
}
void change(int l,int r,int val)
{
    for(int i=l;i<=min(blo*bl[l],r);i++)
    {
        v[i]+=val;
    }
    reset(bl[l]);
    if(bl[l]!=bl[r])
    {
        for(int i=(bl[r]-1)*blo+1;i<=r;i++)
        v[i]+=val;
        reset(bl[r]);
    }
    for(int i=bl[l]+1;i<=bl[r]-1;i++)
    lazy[i]+=val;
}
int query(int l,int r,int val)
{
    int ans=0;
    for(int i=l;i<=min(r,bl[l]*blo);i++)
    if(v[i]+lazy[bl[l]]<val)ans++;
    if(bl[l]!=bl[r])
    {
        for(int i=blo*(bl[r]-1)+1;i<=r;i++)
        if(v[i]+lazy[bl[r]]<val) ans++;
    }
    for(int i=bl[l]+1;i<=bl[r]-1;i++)
    ans+=lower_bound(vec[i].begin(),vec[i].end(),val-lazy[i])-vec[i].begin();
    return ans;

}
int main()
{
    scanf("%d %d",&n,&m);
    blo=sqrt(n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&v[i]);
        bl[i]=(i-1)/blo+1;
        vec[bl[i]].push_back(v[i]);
    }
    for(int i=1;i<=bl[n];i++)
    sort(vec[i].begin(),vec[i].end());
    char char_[2];
    for(int i=1;i<=m;i++)
    {
        int x,y,z;
        scanf("%s %d %d %d",char_,&x,&y,&z);
        if(char_[0]==‘C‘)
        {
            change(x,y,z);
        }else
        {
            int l=1,r=1e9,mid;
            while(l<r)
            {

                mid=(l+r+1)>>1;
                //cout<<l<<‘ ‘<<r<<‘ ‘<<mid<<endl;
                int tt=query(x,y,mid)+1;
                if(tt<z)
                {
                    l=mid+1;
                }else if(tt>z) r=mid-1;else l=mid;
            }
            printf("%d\n",r);
        }

    }

}
时间: 2024-10-05 04:45:25

区间第k大数的相关文章

[csu/coj 1080]划分树求区间前k大数和

题意:从某个区间内最多选择k个数,使得和最大 思路:首先题目给定的数有负数,如果区间前k大出现负数,那么负数不选和更大,于是对于所有最优选择,负数不会出现,所以用0取代负数,问题便转化为区间的前k大数和. 划分树: [1  6  3  8  5  4  7  2] [6  8  5  7][1  3  4  2] [8  7][6  5][3  4][1  2] [8][7][6][5][4][3][2][1] 把快排的结果从上至下依次放入线段树,就构成了划分树,划分的意思就是选定一个数,把原序

POJ 2104 K-th Number(区间第k大数)(平方分割,归并树,划分树)

题目链接: http://poj.org/problem?id=2104 解题思路: 因为查询的个数m很大,朴素的求法无法在规定时间内求解.因此应该选用合理的方式维护数据来做到高效地查询. 如果x是第k个数,那么一定有 (1)在区间中不超过x的数不少于k个 (2)在区间中小于x的数有不到k个 因此,如果可以快速求出区间里不超过x的数的个数,就可以通过对x进行二分搜索来求出第k个数是多少. 接下来,我们来看一下如何计算在某个区间里不超过x个数的个数.如果不进行预处理,那么就只能遍历一遍所有元素.

POJ 2104 K-th Number(区间第k大数)(平方切割,归并树,划分树)

题目链接: http://poj.org/problem? id=2104 解题思路: 由于查询的个数m非常大.朴素的求法无法在规定时间内求解. 因此应该选用合理的方式维护数据来做到高效地查询. 假设x是第k个数,那么一定有 (1)在区间中不超过x的数不少于k个 (2)在区间中小于x的数有不到k个 因此.假设能够高速求出区间里不超过x的数的个数.就能够通过对x进行二分搜索来求出第k个数是多少. 接下来,我们来看一下怎样计算在某个区间里不超过x个数的个数. 假设不进行预处理,那么就仅仅能遍历一遍全

【poj2104-求区间第k大数(不修改)】主席树/可持续化线段树

第一道主席树~然而是道比较水的...因为它不用修改... 转载一个让我看懂的主席树的讲解吧:http://blog.csdn.net/regina8023/article/details/41910615 (未授权,侵权删) --------------------------------------------------------------------------------------------------------------------- 那么如果要询问i-j之间数字出现的次数

POJ2104-K-th Number-求区间第K大数(暴力or归并树or划分树)

题目链接:http://poj.org/problem?id=2104 题目意思很简单,就是给你一个序列,查询某区间第K大的数: 方法1:时间复杂度O(N*M):不支持更新操作,代码简单: 利用结构体排序,保留原数据的顺序. #include <stdio.h> #include <iostream> #include <algorithm> #define N 100000 using namespace std; /* 这个思路很好:时间复杂度O(n*m): 不过还

主席树的各类模板(区间第k大数【动,静】,区间不同数的个数,区间&lt;=k的个数)

取板粗 1.(HDOJ2665)http://acm.hdu.edu.cn/showproblem.php?pid=2665 (POJ2104)http://poj.org/problem?id=2104 (POJ2761)http://poj.org/problem?id=2761 题意:求区间第K大,主席树模板题 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; t

[POJ2104] 区间第k大数 [区间第k大数,可持久化线段树模板题]

可持久化线段树模板题. #include <iostream> #include <algorithm> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <ctime> #include <vector> using namespace std; int n,q,tot,a[110000]; in

POJ 2761 Feed the dogs(树状数组求区间第K大)

题目链接: 戳我 题目大意:Jiajia要为宠物狗,宠物狗按成一排站好(1 < i <= n),第 i 只狗的喜欢程度是 a[i], 之后他会先喂某个区间内第k个 即 n 个数, m个询问,接着是 n个数 接下来 m 行,每行是 l r k即 l 到 r 这个区间第 k 小的数,每个询问输出一个答案,即 a[i] 求区间第k大有很多算法, 详见此博客 [数据结构练习] 求区间第K大数的几种方法 我用的树状数组解法,来自 树状数组从前往后求和,用来解第k大(或小)的数 poj 2985 The

数据结构之区间K大数

求区间的问题有很多类,虽然前人有很多讲解了: 但是我在这里在普及一下,算是自己的一种复习吧. 1.静态询问一个区间的的第k大数,比如询问[l,r] k大数.虽然主席树可以处理,但是这类问题应该是划分树最合适的地方. 划分树--- 实际上是利用大概一种类似快排的思想 来求解第K大数. 建树 建树的过程比较简单,对于区间[l,r],首先通过对原数组的排序找到这个区间的中位数a[mid],小于a[mid]的数划入他的左子树[l,mid-1],大于它的划入右子树[mid,r].同时,对于第i个数,记录在