题目链接:hdu5412
题意:
这是一道经典的主席树题目,带修改的区间第k大查询。
题解:
我学习了整体二分的方法,以这种常数小,代码短方法来重新解决这个问题。
对于初始数字,变为插入操作
按操作的时间顺序排列各个操作,对于修改操作拆为删除和加入操作:
1 删除之前插入的数字,2. 加入新的数字
接下来分治二分答案:
对于mid,如果插入或者删除的数字<=mid那么应该放到左区间,并且用树状数组(其他数据结构也行)维护前X个位置有多少个数字在左边。
对于询问:如果l,r区间在左边的数字>=k那么答案在左边,否则答案在右边,并且更新K,k=k-这个区间去左边的数字个数
当low =high的时候,说明low就是答案了,只要更新询问还在low,low之间的答案即可。
复杂度分析:分治的深度是log(S)s是数据的范围。
每个询问每次被分到左边或者右边,会有log(s)次操作。每个插入或者删除也是。
但是要用树状数组维护多少个数字在左边,要log(n)次更新或者查询。
复杂度是n*log(s)*log(n)
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn=300010;
int n,q,cnt;
struct Event{
int t,type,l,r,num,ans;
}event[maxn];
struct BIT{
int s[maxn];
int lowbit(int a){
return a&(-a);
}
void add(int a,int b){
for (int i=a;i<maxn;i+=lowbit(i)) s[i]+=b;
}
int query(int a){
int ans=0;
for (int i=a;i;i-=lowbit(i)) ans+=s[i];
return ans;
}
}tree;
int store[maxn];
int id[maxn],id2[maxn];
bool cmp(int a,int b){
return event[a].t<event[b].t;
}
void erfen(int L,int R,int low,int high){
if (L>R) return;
if (low==high){
for (int i=L;i<=R;i++) event[id[i]].ans=low;
return;
}
int l=L,r=R,mid=(low+high)>>1;
for (int i=L;i<=R;i++)
if (event[id[i]].type==2){
int k=tree.query(event[id[i]].r)-tree.query(event[id[i]].l-1);
if (k>=event[id[i]].num)
id2[l++]=id[i];
else{
event[id[i]].num-=k;
id2[r--]=id[i];
}
}
else{
if (event[id[i]].num<=mid){
tree.add(event[id[i]].l,event[id[i]].type);
id2[l++]=id[i];
}
else id2[r--]=id[i];
}
for (int i=L;i<l;i++)
id[i]=id2[i];
for (int i=R;i>r;i--)
id[l+R-i]=id2[i];
for (int i=L;i<l;i++)
if (event[id[i]].type!=2)
tree.add(event[id[i]].l,-event[id[i]].type);
erfen(L,l-1,low,mid);
erfen(l,R,mid+1,high);
}
int main(){
freopen("5412.in","r",stdin);
freopen("5412.out","w",stdout);
while (scanf("%d",&n)!=EOF){
cnt=0;
for (int i=1;i<=n;i++){
scanf("%d",&store[i]);
event[++cnt]=(Event){cnt,1,i,i,store[i],0};
}
scanf("%d",&q);
for (int i=1;i<=q;i++){
int type;
scanf("%d",&type);
if (type==1){
int a,b;
scanf("%d%d",&a,&b);
event[++cnt]=(Event){cnt,-1,a,a,store[a],0};
store[a]=b;
event[++cnt]=(Event){cnt,1,a,a,store[a],0};
}
else{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
event[++cnt]=(Event){cnt,2,a,b,c,0};
}
}
for (int i=1;i<=cnt;i++) id[i]=i;
sort(id+1,id+cnt+1,cmp);
erfen(1,cnt,1,1000000000);
for (int i=1;i<=cnt;i++)
if (event[i].type==2)
printf("%d\n",event[i].ans);
}
fclose(stdin);
fclose(stdout);
return 0;
}