Old Problem [带修改的kth]
来源:互联网 发布:脱口秀大会 知乎 编辑:程序博客网 时间:2024/06/05 23:43
这是一个经典问题
n个数的数列A[1…n]
q次操作 :
1 L R x 区间[L,R] 加 x
2 L R k 询问区间[L,R] 第k大的数
这个问题陈老师在一篇论文中给了3种方法
我选择了实现比较简单的 二分+分块
#include<cstdio>#include<cmath>#include<algorithm>using namespace std;const int MAXN=1e5+5,NUM=2e3;int A[MAXN],sA[MAXN],tag[NUM],n,m,num;inline void build(){ for(int i=0;i<=n/num;i++){ tag[i]=0; } for(int i=0;i<=n;i++){ sA[i]=A[i]; } for(int i=0;i<n/num;i++){ sort(sA+i*num,sA+i*num+num); }}inline void change(int l,int r,int t){ if(l/num==r/num){ for(int i=l;i<=r;i++){ A[i]+=t; } if(r/num==n/num) return ; for(int i=l/num*num;i<r/num*num+num;i++){ sA[i]=A[i]; } sort(sA+l/num*num,sA+r/num*num+num); return ; } for(int i=l/num+1;i<r/num;i++){ tag[i]+=t; } for(int i=l;i<l/num*num+num;i++){ A[i]+=t; } for(int i=l/num*num;i<l/num*num+num;i++){ sA[i]=A[i]; } sort(sA+l/num*num,sA+l/num*num+num); for(int i=r/num*num;i<=r;i++){ A[i]+=t; } if(r/num==n/num) return ; for(int i=r/num*num;i<r/num*num+num;i++){ sA[i]=A[i]; } sort(sA+r/num*num,sA+r/num*num+num);}inline int query(int l,int r,int qn){ int cnt=0; if(l/num==r/num){ for(int i=l;i<=r;i++){ if(A[i]+tag[i/num]<=qn){ cnt++; } } return cnt; } for(int i=l;i<l/num*num+num;i++){ if(A[i]+tag[i/num]<=qn){ cnt++; } } for(int i=r/num*num;i<=r;i++){ if(A[i]+tag[i/num]<=qn){ cnt++; } } for(int i=l/num+1;i<r/num;i++){ cnt+=upper_bound(sA+i*num,sA+i*num+num,qn-tag[i])-(sA+i*num); } return cnt;}inline int getkth(int l,int r,int k){ int low=-1e9,top=1e9; while(top-low>1){ int mid=(top+low)>>1; int kk=query(l,r,mid); if(kk>=k) top=mid; else low=mid; } return top;}int main(){// freopen("out","r",stdin);// freopen("myans","w",stdout); while(scanf("%d",&n)!=EOF){ num=sqrt(n*log(n)/log(2)); n--; for(int i=0;i<=n;i++) scanf("%d",&A[i]); build(); scanf("%d",&m); while(m--){ int op,l,r,x; scanf("%d%d%d%d",&op,&l,&r,&x); l--,r--; if(op==1){ change(l,r,x); }else{ int ans=getkth(l,r,x); printf("%d\n",ans); } } } return 0;}
第一次写分块,写了个验证程序,也附上吧
数据生成
#include<stdio.h>#include<stdlib.h>#include<time.h>const int MAXN=1e5+5;const int T=10;int A[MAXN];int main(){ freopen("out","w",stdout); for(int i=0;i<T;i++){ srand((unsigned int)(time(NULL))); int n=rand()+17; printf("%d\n",n); for(int i=0;i<n;i++) printf("%d ",rand()<(rand()+10000)?rand():-rand()); int m=rand()%1234; printf("\n%d\n",m); while(m--){ int op=rand()%2+1; int l=rand()%(n/2+1)+1; int r=l+rand()%(n/2+1); int x=op==1?(rand()<(rand()+10000)?rand():-rand()):(rand()%(r-l+1)+1); printf("%d %d %d %d\n",op,l,r,x); } } return 0;}
暴力验证
#include<stdio.h>#include<algorithm>using namespace std;const int MAXN=1e5+5;int A[MAXN],B[MAXN],n,m;int main(){ freopen("out","r",stdin); freopen("ans","w",stdout); while(scanf("%d",&n)!=EOF){ for(int i=1;i<=n;i++) scanf("%d",&A[i]); scanf("%d",&m); int op,l,r,x; while(m--){ scanf("%d%d%d%d",&op,&l,&r,&x); if(r>n||l>r) {puts("error");exit;} if(op==1){ for(int i=l;i<=r;i++) A[i]+=x; }else{ for(int i=l;i<=r;i++) B[i]=A[i]; sort(B+l,B+r+1); printf("%d\n",B[l+x-1]); } } } return 0;}
阅读全文
0 0
- Old Problem [带修改的kth]
- An Old Problem
- HDU-2665 Kth number (主席树 不带修改区间第k大)
- XDOJ An Old Problem 水水水
- ZOJ Problem Set - 2679 Old Bill
- 带修改的主席树
- Problem 61 修改进程的显示名称
- old
- 怎样修改带密码的还原精灵
- Oracle 修改带数据的字段类型
- Oracle 修改带数据的字段类型
- 修改myeclipse自带libraries的方法
- Oracle 修改带数据的字段类型
- 修改VS自带的模版文件
- Oracle 修改带数据的字段类型
- Oracle 修改带数据的字段类型
- Oracle 修改带数据的字段类型
- Oracle 修改带数据的字段类型
- 《数据结构与算法分析—Java语言描述》pdf
- CSS样式有哪些常用的属性?
- spring jdbc 使用详解
- Android开发:为什么创建MyApplication类笔记
- 《Python算法教程_中文版》pdf
- Old Problem [带修改的kth]
- 关联式容器
- TCP/UDP保护消息边界
- 登陆网络请求的Retrofit实现【新手】
- android动态权限工具类
- python:浅析python 中__name__ = '__main__' 的作用
- 《Web渗透技术及实战案例解析》pdf
- wifi display
- LeetCode 438. Find All Anagrams in a String