题目链接:点这里!!!!
题意:带修改的求区间第K大
题解:
带修改的求区间第K大,很容易想到的一个做法是主席树。
但是注意一下数据的范围,n<=100000。如果用主席树的话,会直接TLE+MLE。
所以主席树在这道题上是不可行的。我们考虑别的做法,我们注意到这道题可以离线处理,基于离线,我们就可以用整体二分来做这道题。
对于一个区间[L,R],我们假设一个数s,求得区间里小于等于s的数的个数为num,如果num>=k,答案肯定小于等于s;如果num<k,答案肯定大于s。
利用这点,我们可以将所有询问一起二分。
我们对所有询问二分答案,然后判断每个询问的答案是否大于当前标准,按照此规定将询问划分成两部分,递归解决。
操作分为三种:
1、给x位置增加一个数v
2、给x位置删除一个数v
3、询问[l,r]中<=mid的数的个数是否<K,mid作为判断的标准。
直接递归就能解决。
如果还有不懂直接看代码吧。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<sstream>
#include<algorithm>
#include<vector>
#include<bitset>
#include<set>
#include<queue>
#include<stack>
#include<map>
#include<cstdlib>
#include<cmath>
#define PI 2*asin(1.0)
#define LL long long
#define pb push_back
#define pa pair<int,int>
#define clr(a,b) memset(a,b,sizeof(a))
#define lson lr<<1,l,mid
#define rson lr<<1|1,mid+1,r
#define bug(x) printf("%d++++++++++++++++++++%d\n",x,x)
#define key_value ch[ch[root][1]][0]C:\Program Files\Git\bin
const int MOD = 1000000007;
const int N = 1e5+15;
const int maxn = 3e5+1000;
const int letter = 130;
const int INF = 1e17;
const double pi=acos(-1.0);
const double eps=1e-8;
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
///N 1e5
///maxn 3e5
int n,q,a[maxn],tot;
int p1[maxn],p2[maxn],ans[maxn];
int c[maxn];
struct node{
int id,l,r,v;
///id -1 +1 2
}qu[maxn];
void addqu(int id,int l,int r,int v){
qu[tot].id=id,qu[tot].l=l,qu[tot].r=r,qu[tot].v=v,p1[tot]=tot++;
}
int lowbit(int x){
return x&(-x);
}
void update(int x,int val){
while(x<=n){
c[x]+=val;
x+=lowbit(x);
}
}
int getsum(int x){
int ans=0;
while(x>0){
ans+=c[x];
x-=lowbit(x);
}
return ans;
}
void solve(int L,int R,int low,int high){
if(L>R) return;
if(low==high){
while(L<=R){
if(qu[p1[L]].id==2) ans[p1[L]]=low;
L++;
}
return;
}
int mid=(low+high)/2,j,len;
int l=L,r=R;
for(int i=L;i<=R;i++){
j=p1[i];
if(qu[j].id==2){
len=getsum(qu[j].r)-getsum(qu[j].l-1);
if(len<qu[j].v) qu[j].v-=len,p2[r--]=j;
else p2[l++]=j;
}
else {
if(qu[j].v<=mid) update(qu[j].l,qu[j].id),p2[l++]=j;
else p2[r--]=j;
}
}
for(int i=L;i<=R;i++){
j=p1[i];
if(qu[j].id!=2&&qu[j].v<=mid) update(qu[j].l,-qu[j].id);
}
int i=L;
for(i=L;i<l;i++)p1[i]=p2[i];
for(r=R;i<=R;r--,i++) p1[i]=p2[r];
solve(L,l-1,low,mid);
solve(l,R,mid+1,high);
}
///hdu 5412
int main(){
int id,x,y,z;
while(scanf("%d",&n)!=EOF){
tot=0;
int max1=-1;
for(int i=1;i<=n;i++){
scanf("%d",a+i);
addqu(1,i,i,a[i]);
max1=max(max1,a[i]);
}
scanf("%d",&q);
for(int i=0;i<q;i++){
scanf("%d%d%d",&id,&x,&y);
if(id==1){
addqu(-1,x,x,a[x]);
a[x]=y;
addqu(1,x,x,a[x]);
max1=max(max1,y);
}
else {
scanf("%d",&z);
addqu(2,x,y,z);
}
}
/// printf("%d\n",max1);
solve(0,tot-1,1,max1);
for(int i=0;i<tot;i++) {
if(qu[i].id==2) {
printf("%d\n",ans[i]);
}
}
}
return 0;
}
/*
10
2 100 23 7 2 3 6 3 1 9
7
2 1 10 2
2 1 4 3
1 2 1
2 1 6 1
2 1 10 2
1 4 1000
2 1 9 9
*/