首页 > 代码库 > 区间第k大数

区间第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);
        }
        
    }
    
}

 

区间第k大数