POJ2104 K-th Number [分块做法]
Posted Candy?
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ2104 K-th Number [分块做法]相关的知识,希望对你有一定的参考价值。
传送:主席树做法http://www.cnblogs.com/candy99/p/6160704.html
做那倒带修改的主席树时就发现分块可以做,然后就试了试
思想和教主的魔法差不多,只不过那个是求>=v的有几个
既然一个数v的名次可以求,我们二分这个数就行了啊
然而......
首先,你二分到的这个数不一定在区间里出现过
比如 1 2 5 8 9
4和5的名次都是3
于是,我修改了某个区间名次的定义:
“如果一个数的名次是x,但是区间中没有次数,那么他的名次为x-1”
实现上只需要find里return l-t+(b[l]==v) 等于说明出现过
然而
该死不写了鬼知道怎么回事用主席树就行了
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; typedef long long ll; const int N=1e5+500; inline int read(){ char c=getchar();int x=0,f=1; while(c<\'0\'||c>\'9\'){if(c==\'-\')f=-1; c=getchar();} while(c>=\'0\'&&c<=\'9\'){x=x*10+c-\'0\'; c=getchar();} return x*f; } int n,Q,a[N],bl,m,b[N],pos[N]; int mp[N]; void reset(int x){ int l=(x-1)*bl+1,r=min(x*bl,n); for(int i=l;i<=r;i++) b[i]=a[i]; sort(b+l,b+r+1); } int flag; int find(int x,int v){ int l=(x-1)*bl+1,r=min(x*bl,n),t=l; while(l<=r){ int mid=(l+r)>>1; if(b[mid]<v) l=mid+1; else r=mid-1; } if(b[l]==v) flag=1; return l-t+1;//! } int rank(int l,int r,int v){ int ans=0; flag=0; if(pos[l]==pos[r]){ for(int i=l;i<=r;i++) if(a[i]<=v) ans++,flag=flag||a[i]==v; }else{ int t=pos[l]*bl; for(int i=l;i<=t;i++) if(a[i]<=v) ans++,flag=flag||a[i]==v; for(int i=(pos[r]-1)*bl+1;i<=r;i++) if(a[i]<=v) ans++,flag=flag||a[i]==v; for(int i=pos[l]+1;i<pos[r];i++) ans+=find(i,v); } if(!flag) ans--; return ans; } int query(int ql,int qr,int k){ int l=1,r=n; while(l<=r){ int mid=(l+r)>>1; int t=rank(ql,qr,mp[mid]); if(t<k) l=mid+1; else r=mid-1; } return l; } int main(){ freopen("in.txt","r",stdin); freopen("1.out","w",stdout); n=read();Q=read(); bl=sqrt(n); m=n/bl;if(n%bl) m++; for(int i=1;i<=n;i++) a[i]=mp[i]=read(),pos[i]=(i-1)/bl+1; for(int i=1;i<=m;i++) reset(i); sort(mp+1,mp+1+n); while(Q--){ int i=read(),j=read(),k=read(); printf("%d\\n",mp[query(i,j,k)]); } }
#include <map> #include <set> #include <stack> #include <queue> #include <cmath> #include <string> #include <vector> #include <cstdio> #include <cctype> #include <cstring> #include <sstream> #include <cstdlib> #include <iostream> #include <algorithm> #pragma comment(linker,"/STACK:102400000,102400000") using namespace std; #define MAX 100005 #define MAXN 1000005 #define maxnode 15 #define sigma_size 30 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lrt rt<<1 #define rrt rt<<1|1 #define middle int m=(r+l)>>1 #define LL long long #define ull unsigned long long #define mem(x,v) memset(x,v,sizeof(x)) #define lowbit(x) (x&-x) #define pii pair<int,int> #define bits(a) __builtin_popcount(a) #define mk make_pair #define limit 10000 //const int prime = 999983; const int INF = 0x3f3f3f3f; const LL INFF = 0x3f3f; const double pi = acos(-1.0); const double inf = 1e18; const double eps = 1e-8; const LL mod = 1e9+7; const ull mx = 133333331; /*****************************************************/ inline void RI(int &x) { char c; while((c=getchar())<\'0\' || c>\'9\'); x=c-\'0\'; while((c=getchar())>=\'0\' && c<=\'9\') x=(x<<3)+(x<<1)+c-\'0\'; } /*****************************************************/ int a[MAX]; int b[MAX]; int c[MAX]; int tmp; bool judge(int x,int l,int r,int k){ int a1=l/tmp; int a2=r/tmp; int sum=0;//for(int i=l;i<=r;i++) printf("%d ",a[i]);puts(""); if(a1==a2){ for(int i=l;i<=r;i++) if(a[i]<=c[x]) sum++; if(sum>=k) return true; return false; } for(int i=a1+1;i<a2;i++){ sum+=upper_bound(b+i*tmp,b+(i+1)*tmp,c[x])-b-i*tmp; } for(int i=l;i<(a1+1)*tmp;i++) if(a[i]<=c[x]) sum++; for(int i=a2*tmp;i<=r;i++) if(a[i]<=c[x]) sum++; //printf("ra %d %d %d %d\\n",l,r,c[x],sum); if(sum>=k) return true; return false; } int main(){ freopen("in.txt","r",stdin); freopen("2.out","w",stdout); int n,m; scanf("%d%d",&n,&m); tmp=sqrt(n); for(int i=0;i<n;i++){ scanf("%d",&a[i]); b[i]=a[i]; c[i]=a[i]; } sort(c,c+n); for(int i=0;i*tmp<n;i++){ if((i+1)*tmp<=n) sort(b+i*tmp,b+(i+1)*tmp); else sort(b+i*tmp,b+n); } while(m--){ int l,r,k; scanf("%d%d%d",&l,&r,&k); int ll=0,rr=n-1; while(ll<=rr){ int mid=(ll+rr)>>1; if(judge(mid,l-1,r-1,k)) rr=mid-1; else ll=mid+1; } printf("%d\\n",c[ll]); } return 0; }
以上是关于POJ2104 K-th Number [分块做法]的主要内容,如果未能解决你的问题,请参考以下文章