参考博客由于国庆hdu升级进不去,尝试了ZOJ2112 空间消耗减少了20000多
在学习区间第k大时,学了主席树,主席树空间消耗很大,有些题过不了,然后又开始学整体二分,记录下个人理解
整体二分正如他的名字,把所有操作和查询放一起,二分查找答案,开始时,我也很懵逼,这怎么实现。。。。。。。。。
后面通过看别人代码,发现也不难理解,他的整体操作就是,先把所有的输入记录下来,就是离线,把修改操作分为连续的两步操作,一步是把第x位的修改前num的个数减一,把第x位的修改后num加1,类似树状数组套主席树的修改,而前n个输入就是一步直接加上num,写一个结构体,用个op标记,op=2,表示查询,op=1表示插入,op=-1,表示删除某个数,这样就把输入的n个数和q个操作合为了一个整体,再然后就是离散数据后,对数据进行二分查找答案,
#include<bits/stdc++.h>
using namespace std;
#define MAXN 100010
#define lowbit(x) x&(-x)
struct Node
{
int op,x,y,k,id;
}qu[MAXN*3],q1[MAXN<<1],q2[MAXN<<1];
int a[MAXN],num[MAXN<<1],sum[MAXN],n,ans[MAXN];
void update(int x,int v)
{
while(x<=n)
{
sum[x]+=v;
x+=lowbit(x);
}
}
int query(int x)
{
int res=0;
while(x>0)
{
res+=sum[x];
x-=lowbit(x);
}
return res;
}
void solve(int x,int y,int l,int r)//x到y操作 l到r答案
{
if(l==r)
{
for(int i=x;i<=y;i++)
{
if(qu[i].op==2)ans[qu[i].id]=num[l];
}
return;
}
int mid=(l+r)/2,c1=0,c2=0;
for(int i=x;i<=y;i++)
{
if(qu[i].op==2)
{
int d=query(qu[i].y)-query(qu[i].x-1);
if(qu[i].k<=d)
{
q1[c1++]=qu[i];
} else
{
qu[i].k-=d;
q2[c2++]=qu[i];
}
} else
{
if(qu[i].y<=mid)
{
update(qu[i].x,qu[i].op);
q1[c1++]=qu[i];
} else q2[c2++]=qu[i];
}
}
for(int i=0;i<c1;i++)
{
if(q1[i].op!=2)update(q1[i].x,-q1[i].op);
}
memcpy(qu+x,q1,sizeof(Node)*c1);
memcpy(qu+x+c1,q2,sizeof(Node)*c2);
solve(x,x+c1-1,l,mid);
solve(x+c1,y,mid+1,r);
}
void write(int q)
{
for(int i=0;i<q;i++)
{
printf("%d\n",ans[i]);
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--) {
int q,x,y,k;
// memset(sum,0,sizeof(sum));
scanf("%d %d",&n,&q);
int all = 1, tot = 0,query_id=0;
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
num[tot++]=a[i];
qu[all++]={1,i,a[i]};
}
scanf("%d",&q);
char op[2];
for(int i=0;i<q;i++)
{
scanf("%s %d %d",op,&x,&y);
if(op[0]=='Q')
{
scanf(" %d",&k);
qu[all++]={2,x,y,k,query_id++};
} else
{
qu[all++]={-1,x,a[x]};
qu[all++]={1,x,y};
a[x]=y;
num[tot++]=y;
}
}
sort(num,num+tot);
int cnt=unique(num,num+tot)-num;
for(int i=1;i<all;i++)
{
if(qu[i].op!=2)
{
qu[i].y=lower_bound(num,num+cnt,qu[i].y)-num;
}
}
solve(1,all-1,0,cnt-1);
write(query_id);
}
return 0;
}