【HDU5412】CRB and Queries-整体二分:带修改区间第K小
2017-05-07 11:37
489 查看
测试地址:CRB and Queries
题目大意:维护一个数列A,要求支持两种操作:1.修改一个元素;2.给定K,询问某一个区间的第K小元素。
做法:经典的带修改区间第K小,本人使用树状数组套主席树完成过和这题题意一致的题,题解在这里。后来本人学习了整体二分这一思想,运用这一思想可以更加简便的完成这一道题,接下来我们就来看看整体二分的思想以及如何运用它来解决这一道题。
我们知道要求区间第K小,就是要在询问区间内求一个值,使得在询问区间内小于这个值的数小于K,并且小于等于这个值的数大于等于K,这个性质是单调的,如果只有一个询问,我们可以二分答案+树状数组统计来完成这一任务。那么扩展到多个询问,单纯的二分就不能解决这一问题了,所以我们使用整体二分的思想。
整体二分是通过二分答案的取值区间,同时把操作归到对应的取值区间里。一般整体二分的主体都是一个函数solve(s,t,l,r),表示操作区间[s,t]内询问的答案或者要修改的量都在取值区间[l,r]内。一般解题的步骤是这样的:
1.确定区间中点mid=l+r2,统计当答案等于mid时,操作区间[s,t]内询问的信息。
2.将取值区间分割为[l,mid]和[mid+1,r]两个区间,根据各个询问的信息将询问重新排列,向下递归处理。
显然可见,如果l=r,那么操作区间[s,t]内的所有询问的答案就是l。
把这个思想带到这一题中,那么解题的思路就很显然了,统计的时候使用树状数组就行了,复杂度O(Nlog2N),和树状数组套主席树同阶,显然整体二分代码量小一些,而且思路也比较清晰。到了这一步还不理解的话就看代码吧。
以下是本人代码:
题目大意:维护一个数列A,要求支持两种操作:1.修改一个元素;2.给定K,询问某一个区间的第K小元素。
做法:经典的带修改区间第K小,本人使用树状数组套主席树完成过和这题题意一致的题,题解在这里。后来本人学习了整体二分这一思想,运用这一思想可以更加简便的完成这一道题,接下来我们就来看看整体二分的思想以及如何运用它来解决这一道题。
我们知道要求区间第K小,就是要在询问区间内求一个值,使得在询问区间内小于这个值的数小于K,并且小于等于这个值的数大于等于K,这个性质是单调的,如果只有一个询问,我们可以二分答案+树状数组统计来完成这一任务。那么扩展到多个询问,单纯的二分就不能解决这一问题了,所以我们使用整体二分的思想。
整体二分是通过二分答案的取值区间,同时把操作归到对应的取值区间里。一般整体二分的主体都是一个函数solve(s,t,l,r),表示操作区间[s,t]内询问的答案或者要修改的量都在取值区间[l,r]内。一般解题的步骤是这样的:
1.确定区间中点mid=l+r2,统计当答案等于mid时,操作区间[s,t]内询问的信息。
2.将取值区间分割为[l,mid]和[mid+1,r]两个区间,根据各个询问的信息将询问重新排列,向下递归处理。
显然可见,如果l=r,那么操作区间[s,t]内的所有询问的答案就是l。
把这个思想带到这一题中,那么解题的思路就很显然了,统计的时候使用树状数组就行了,复杂度O(Nlog2N),和树状数组套主席树同阶,显然整体二分代码量小一些,而且思路也比较清晰。到了这一步还不理解的话就看代码吧。
以下是本人代码:
#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; }
相关文章推荐
- hdu 5412 CRB and Queries(动态区间第k大值,区间能修改)(整体二分,树状数组套平衡树,线段树套treap)
- 整体二分,区间第K小(CRB and Queries,HDU 5412)
- hdu 5412 CRB and Queries(动态求区间第k小+整体二分)
- HDU 5412 CRB and Queries 求区间第k小 CDQ分治+整体二分
- hdu5412--CRB and Queries(整体二分)
- 整体二分 hdu5412 CRB and Queries
- hdu5412 CRB and Queries (整体二分)
- 整体二分初探 两类区间第K大问题 poj2104 & hdu5412
- 【ZOJ2112】【整体二分+树状数组】带修改区间第k大
- HDU 5412 CRB and Queries (Kth number 整体二分 动态转静态)
- 【BZOJ 3110】 [Zjoi2013]K大数查询 整体二分+树状数组区间修改
- HDU 5412 CRB and Queries 整体二分
- 【XSY2720】区间第k小 整体二分 可持久化线段树
- Hdu-5412 CRB and Queries(整体二分)
- 2017 暑假艾教集训 day10 (补zoj2112带修改的第k大)整体二分
- hdu 2104 K-th Number(静态求区间第k小+整体二分)
- bzoj1901[Zju2112] Dynamic Rankings / hdu5412 CRB and Queries 整体二分基础摸板
- [HDU 5412] CRB and Queries (整体二分)
- HDU 5412 CRB and Queries(整体二分 | CDQ分治)
- hdu 5412 CRB and Queries(线段树套笛卡尔树 - 动态区间第k大)