整体二分求区间第k大模板(POJ 2104)
自己的模板,线段树实现的,可以参考一下
算法步骤
参考一下文章
http://www.cnblogs.com/dirge/articles/5810855.html
https://www.cnblogs.com/rayrayrainrain/articles/6477611.html
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
using namespace std;
#define mem(a,val) memset(a,val,sizeof a)
#define fori(l,r) for( int i = l ; i <= r ; i++ )
#define forj(l,r) for( int j = l ; j <= r ; j++ )
#define fork(l,r) for( int k = l ; k <= r ; k++ )
#define inf 0x3f3f3f3f
#define lef rt<<1
#define rig rt<<1|1
#define mid (l+r)>>1
int n,qcnt;
const int maxn = 2e5+5;
struct spe
{
int type;
int l,r; //求区间k大的左右范围
int k,pos,val; //第k大,pos为单点修改的位置
};
spe q[maxn];
int ans[maxn];
spe lq[maxn],rq[maxn];
int tree[maxn<<2];
void updatePoint( int l,int r,int rt,int pos,int val )
{
if( l == r )
{
tree[rt] += val;
return;
}
int m = mid;
if( m >= pos )
updatePoint(l,m,lef,pos,val);
else updatePoint(m+1,r,rig,pos,val);
tree[rt] = tree[lef]+tree[rig];
}
int L,R;
int query( int l,int r,int rt )
{
if( l >= L && r <= R )
return tree[rt];
int ans = 0;
int m = mid;
if( m >= L )
ans += query(l,m,lef);
if( m < R )
ans += query(m+1,r,rig);
return ans;
}
void solve( int head,int tail,int l,int r )
{
if( head > tail )
return;
if( l == r ) //存储答案
{
//cout<<l<<" "<<r<<endl;
fori(head,tail)
if( q[i].type == 2 ) //如果是询问类型
{
ans[ q[i].pos ] = l;
//cout<<"yes";
}
return;
}
int m = mid;
int lcnt = 1,rcnt = 1;
fori(head,tail)
{
if( q[i].type == 1 ) //修改点类型
{
if( q[i].val <= m ) //小于m,这个会对后面查询有影响,所以需要更新
{
lq[lcnt++] = q[i];
updatePoint(1,n,1,q[i].pos,1); //表示这个位置有1个数
}
else rq[rcnt++] = q[i];
}
else if( q[i].type == 2 )
{
L = q[i].l , R = q[i].r;
int num = query(1,n,1);
//cout<<" num : "<<num<<endl;
if( num >= q[i].k )
lq[lcnt++] = q[i];
else
{
q[i].k -= num;
rq[rcnt++] = q[i];
}
}
}
lcnt--; //左闭右闭区间,所以-1
rcnt--;
fori(1,lcnt) //还原之前的更新
{
if( lq[i].type == 1 )
updatePoint(1,n,1,lq[i].pos,-1);
}
//更新q
int start = head-1;
fori(1,lcnt)
q[start+i] = lq[i];
start = head+lcnt-1;
fori(1,rcnt)
q[start+i] = rq[i];
solve(head,head+lcnt-1,l,m); //递归解决
solve(head+lcnt,tail,m+1,r);
}
int main()
{
while( scanf("%d %d",&n,&qcnt) == 2 )
{
int ansCnt = qcnt;
mem(tree,0);
qcnt += n;
fori(1,n)
{
scanf("%d",&q[i].val);
q[i].type = 1;
q[i].pos = i;
}
fori(1,ansCnt)
{
scanf("%d %d %d",&q[i+n].l,&q[i+n].r,&q[i+n].k);
q[i+n].type = 2;
q[i+n].pos = i; //这里的pos是为了存储答案,放到ans数组
}
solve(1,qcnt,-inf,inf);
fori(1,ansCnt)
printf("%d\n",ans[i]);
}
}
/*
7 3
1 5 2 6 3 7 4
2 5 3
4 4 1
1 7 3
*/