【HDU5412】CRB and Queries-整体二分:带修改区间第K小
测试地址:CRB and Queries
题目大意:维护一个数列
做法:经典的带修改区间第K小,本人使用树状数组套主席树完成过和这题题意一致的题,题解在这里。后来本人学习了整体二分这一思想,运用这一思想可以更加简便的完成这一道题,接下来我们就来看看整体二分的思想以及如何运用它来解决这一道题。
我们知道要求区间第K小,就是要在询问区间内求一个值,使得在询问区间内小于这个值的数小于K,并且小于等于这个值的数大于等于K,这个性质是单调的,如果只有一个询问,我们可以二分答案+树状数组统计来完成这一任务。那么扩展到多个询问,单纯的二分就不能解决这一问题了,所以我们使用整体二分的思想。
整体二分是通过二分答案的取值区间,同时把操作归到对应的取值区间里。一般整体二分的主体都是一个函数
1.确定区间中点
2.将取值区间分割为
显然可见,如果
把这个思想带到这一题中,那么解题的思路就很显然了,统计的时候使用树状数组就行了,复杂度
以下是本人代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define inf 2000000000
using namespace std;
int n,cnt,qcnt,Q,a[100010],tmp[100010],ans[100010],bit[100010]={0};
struct query
{
int id,x,y,val,cur,k;
}q[300010],a1[300010],a2[300010];
int lowbit(int i)
{
return i&(-i);
}
void add(int x,int d)
{
for(int i=x;i<=n;i+=lowbit(i))
bit[i]+=d;
}
int sum(int x)
{
int s=0;
for(int i=x;i;i-=lowbit(i))
s+=bit[i];
return s;
}
void solve(int s,int t,int l,int r)
{
if (s>t) return;
if (l==r)
{
for(int i=s;i<=t;i++)
if (q[i].val==0) ans[q[i].id]=l;
return;
}
int mid=(l+r)>>1;
for(int i=s;i<=t;i++)
{
if (q[i].val!=0&&q[i].y<=mid) add(q[i].x,q[i].val);
if (q[i].val==0) tmp[q[i].id]=sum(q[i].y)-sum(q[i].x-1);
}
for(int i=s;i<=t;i++)
if (q[i].val!=0&&q[i].y<=mid) add(q[i].x,-q[i].val);
int n1=0,n2=0;
for(int i=s;i<=t;i++)
{
if (q[i].val==0)
{
if (q[i].cur+tmp[q[i].id]>=q[i].k) a1[++n1]=q[i];
else
{
q[i].cur+=tmp[q[i].id];
a2[++n2]=q[i];
}
}
else
{
if (q[i].y<=mid) a1[++n1]=q[i];
else a2[++n2]=q[i];
}
}
for(int i=1;i<=n1;i++) q[s+i-1]=a1[i];
for(int i=1;i<=n2;i++) q[s+n1+i-1]=a2[i];
solve(s,s+n1-1,l,mid);
solve(s+n1,t,mid+1,r);
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
cnt=0,qcnt=0;
int Min=inf,Max=-inf;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
Min=min(Min,a[i]),Max=max(Max,a[i]);
q[++cnt].x=i,q[cnt].y=a[i],q[cnt].val=1;
}
scanf("%d",&Q);
for(int i=1;i<=Q;i++)
{
int op,l,r,k;
scanf("%d",&op);
if (op==1)
{
scanf("%d%d",&l,&k);
q[++cnt].x=l,q[cnt].y=a[l],q[cnt].val=-1;
q[++cnt].x=l,q[cnt].y=k,q[cnt].val=1;
a[l]=k;
Min=min(Min,a[l]),Max=max(Max,a[l]);
}
if (op==2)
{
scanf("%d%d%d",&l,&r,&k);
q[++cnt].x=l,q[cnt].y=r,q[cnt].val=0,q[cnt].id=++qcnt;
q[cnt].k=k,q[cnt].cur=0;
}
}
solve(1,cnt,Min,Max);
for(int i=1;i<=qcnt;i++)
printf("%d\n",ans[i]);
}
return 0;
}