poj2104(K-th Number)
题目链接:传送门
题目大意:给你一个数组,有m次询问,问区间x~y里面第k大的数是什么?
题目思路: 首先谨以此题纪念我即将挂掉的高数大物
这个题是静态区间第K大数,因为后面没有加入新数,很多优秀的数据结构都能解决掉它,推荐一篇博客:传送门
但是为了练习整体二分,于是参照网上博客(传送门),做成了整体二分。
整体二分就是对答案和时间(动态时有效)的双重二分,理解起来稍有难度,理解之后感觉好神奇,再推荐一篇论文:传送门
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cmath> 5 #include <algorithm> 6 #include <cstring> 7 #include <stack> 8 #include <cctype> 9 #include <queue> 10 #include <string> 11 #include <vector> 12 #include <set> 13 #include <map> 14 #include <climits> 15 #define lson root<<1,l,mid 16 #define rson root<<1|1,mid+1,r 17 #define fi first 18 #define se second 19 #define ping(x,y) ((x-y)*(x-y)) 20 #define mst(x,y) memset(x,y,sizeof(x)) 21 #define mcp(x,y) memcpy(x,y,sizeof(y)) 22 using namespace std; 23 #define gamma 0.5772156649015328606065120 24 #define MOD 1000000007 25 #define inf 0x3f3f3f3f 26 #define N 106005 27 #define maxn 5005 28 typedef pair<int,int> PII; 29 typedef long long LL; 30 31 int n,m,k,num; 32 int _min,_max; 33 struct Node{ 34 int id,l,r,v,f; 35 Node(){} 36 Node(int a,int b,int c,int d,int e){ 37 id=a;l=b;r=c;v=d;f=e; 38 } 39 }node[N],t1[N],t2[N]; 40 int hcnt,ans[maxn]; 41 int tree[N]; 42 void add(int i,int v){ 43 for(;i<=n;i+=(i&(-i))) 44 tree[i]+=v; 45 } 46 int query(int i){ 47 int res=0; 48 for(;i;i-=(i&-i)) 49 res+=tree[i]; 50 return res; 51 } 52 void _solve(int ql,int qr,int l,int r){ ///ql,qr是操作的区间,l,r是答案的区间 53 if(ql>qr)return; ///整体二分也是要对答案二分的 54 if(l==r){ ///l==r说明答案已经确定,只要属于这个区间的询问都是这个答案 55 for(int i=ql;i<=qr;++i) 56 if(node[i].f==2) 57 ans[node[i].id]=l; 58 return; 59 } 60 int mid=l+r>>1; 61 int len1=0,len2=0; 62 for(int i=ql;i<=qr;++i){ 63 if(node[i].f==1){ 64 if(node[i].v<=mid){ ///如果数比二分答案小,则它会对后半段操作有影响 65 add(node[i].id,1); 66 t1[len1++]=node[i]; 67 } 68 else t2[len2++]=node[i]; 69 } 70 else{ 71 int temp=query(node[i].r)-query(node[i].l-1);///前面有多少个数,决定之后的划分区间 72 if(node[i].v>temp){ ///如果前面的数小于k个,说明答案在后半段 73 node[i].v-=temp; 74 t2[len2++]=node[i]; 75 } 76 else t1[len1++]=node[i];///与上面同理 77 } 78 } 79 for(int i=0;i<len1;++i)if(t1[i].f==1)add(t1[i].id,-1);///树状数组清空 80 for(int i=0;i<len1;++i){node[ql+i]=t1[i];} 81 for(int i=0;i<len2;++i){node[ql+len1+i]=t2[i];} 82 _solve(ql,ql+len1-1,l,mid); 83 _solve(ql+len1,qr,mid+1,r); 84 } 85 int main(){ 86 int i,j,group,x,y,v; 87 while(scanf("%d%d",&n,&m)!=EOF){ 88 mst(tree,0); 89 hcnt=0;_min=inf;_max=-inf; 90 for(i=1;i<=n;++i){ ///这里我们是把初始给你的数组当作加入操作处理 91 scanf("%d",&x); 92 _min=min(_min,x); 93 _max=max(_max,x); 94 node[++hcnt]=Node(i,1,1,x,1); 95 } 96 for(i=1;i<=m;++i){ 97 scanf("%d%d%d",&x,&y,&v); 98 node[++hcnt]=Node(i,x,y,v,2); 99 } 100 _solve(1,hcnt,_min,_max); 101 for(int i=1;i<=m;++i)printf("%d\n",ans[i]); 102 } 103 return 0; 104 }
还有离散化版本的
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cmath> 5 #include <algorithm> 6 #include <cstring> 7 #include <stack> 8 #include <cctype> 9 #include <queue> 10 #include <string> 11 #include <vector> 12 #include <set> 13 #include <map> 14 #include <climits> 15 #define lson root<<1,l,mid 16 #define rson root<<1|1,mid+1,r 17 #define fi first 18 #define se second 19 #define ping(x,y) ((x-y)*(x-y)) 20 #define mst(x,y) memset(x,y,sizeof(x)) 21 #define mcp(x,y) memcpy(x,y,sizeof(y)) 22 using namespace std; 23 #define gamma 0.5772156649015328606065120 24 #define MOD 1000000007 25 #define inf 0x3f3f3f3f 26 #define N 106005 27 #define maxn 5005 28 typedef pair<int,int> PII; 29 typedef long long LL; 30 31 int a[N],b[N]; 32 int n,m,k,num; 33 int _min,_max; 34 struct Node{ 35 int id,l,r,v,f; 36 Node(){} 37 Node(int a,int b,int c,int d,int e){ 38 id=a;l=b;r=c;v=d;f=e; 39 } 40 }node[N],t1[N],t2[N]; 41 int hcnt,ans[maxn]; 42 int tree[N]; 43 void add(int i,int v){ 44 for(;i<=n;i+=(i&(-i))) 45 tree[i]+=v; 46 } 47 int query(int i){ 48 int res=0; 49 for(;i;i-=(i&-i)) 50 res+=tree[i]; 51 return res; 52 } 53 void _solve(int ql,int qr,int l,int r){ ///ql,qr是操作的区间,l,r是答案的区间 54 if(ql>qr)return; ///整体二分也是要对答案二分的 55 if(l==r){ ///l==r说明答案已经确定,只要属于这个区间的询问都是这个答案 56 for(int i=ql;i<=qr;++i) 57 if(node[i].f==2) 58 ans[node[i].id]=b[l]; 59 return; 60 } 61 int mid=l+r>>1; 62 int len1=0,len2=0; 63 for(int i=ql;i<=qr;++i){ 64 if(node[i].f==1){ 65 if(node[i].v<=mid){ ///如果数比二分答案小,则它会对后半段操作有影响 66 add(node[i].id,1); 67 t1[len1++]=node[i]; 68 } 69 else t2[len2++]=node[i]; 70 } 71 else{ 72 int temp=query(node[i].r)-query(node[i].l-1);///前面有多少个数,决定之后的划分区间 73 if(node[i].v>temp){ ///如果前面的数小于k个,说明答案在后半段 74 node[i].v-=temp; 75 t2[len2++]=node[i]; 76 } 77 else t1[len1++]=node[i];///与上面同理 78 } 79 } 80 for(int i=0;i<len1;++i)if(t1[i].f==1)add(t1[i].id,-1);///树状数组清空 81 for(int i=0;i<len1;++i){node[ql+i]=t1[i];} 82 for(int i=0;i<len2;++i){node[ql+len1+i]=t2[i];} 83 _solve(ql,ql+len1-1,l,mid); 84 _solve(ql+len1,qr,mid+1,r); 85 } 86 int main(){ 87 int i,j,group,x,y,v; 88 //freopen("in.txt","r",stdin); 89 while(scanf("%d%d",&n,&m)!=EOF){ 90 mst(tree,0); 91 hcnt=0;_min=1;_max=n; 92 for(i=1;i<=n;++i){ ///这里我们是把初始给你的数组当作加入操作处理 93 scanf("%d",&a[i]); 94 b[i]=a[i]; 95 } 96 sort(b+1,b+n+1); 97 int len=unique(b+1,b+n+1)-b-1; 98 for(i=1;i<=n;++i){ 99 int loc=lower_bound(b+1,b+len+1,a[i])-b; 100 node[++hcnt]=Node(i,1,1,loc,1); 101 } 102 for(i=1;i<=m;++i){ 103 scanf("%d%d%d",&x,&y,&v); 104 node[++hcnt]=Node(i,x,y,v,2); 105 } 106 _solve(1,hcnt,_min,_max); 107 for(int i=1;i<=m;++i)printf("%d\n",ans[i]); 108 } 109 return 0; 110 }