困死了,完全做不下去题
就当是对莫队最最基本的思想的一个复习叭(只有最最基本的思想,没有莫队)
传送
我们可以很容易的想到这题要用线段树。
60pts
此题要求某个区间里第K小的数,可以暴力的考虑对每个节点所对应的区间排序。这里排序一次可以最快\(O(n)\),查询时也要排序,所以查询一次是\(O(nlogn)\),总复杂度就是\(O(nmlogn)\)。不吸氧60pts。(可能还不如朴素?)
100pts
既然普通线段树不行,那咱就用权值线段树搞搞试试。权值线段树上维护每一个数出现的次数。先离散化,查询时往里扔点,删点即可。题目没有修改,考虑离线做法。我们可以参照莫队的思想,把所有询问的区间记录下来,以左端点为第一关键字,右端点为第二关键字排序。同时设置两个指针l,r,指向上一个处理的区间。当r<当前要处理的区间时,就不断向右移,同时把经过的点扔进权值线段树里。l同理,不过是把经过的点从线段树里删除。每处理完一个区间,就把查询的结果扔进ans数组里,最后输出ans数组即可。
因为题目保证查询的区间互不包含,所以r最多向右移n次,l最多向右移n次,修改与查询都是logn,总复杂度就是\(O(nlogn)\)。突然奇想用树状数组会不会更快?
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<queue> #include<map> #include<vector> #define pa pair<int,int> using namespace std; typedef long long ll; inline int read() { char ch=getchar(); int x=0;bool f=0; while(ch<'0'||ch>'9') { if(ch=='-')f=1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); } return f?-x:x; } const int N=3000001; int n,m,be[N],ae[N],t,ans[50001],l=1,r,sum[4*N]; struct Q{ int l,r,k,id;//记录查询的区间与查询的顺序 }q[50001]; int lower_bound(int kkk)//手写离散化qwq { int ll=1,rr=t; while(ll<=rr) { int mid=(ll+rr)>>1; if(ae[mid]==kkk) return mid; if(ae[mid]>kkk)rr=mid-1; else ll=mid+1; } if(ae[ll]>kkk)ll--;//写丑了.jpg return ll; } void modi(int k,int l,int r,int x,int v) { if(l==r&&l==x) {sum[k]+=v;return ;} int mid=(l+r)>>1; if(x<=mid) modi(k<<1,l,mid,x,v); else modi(k<<1|1,mid+1,r,x,v); sum[k]=sum[k<<1]+sum[k<<1|1]; } int qry(int k,int l,int r,int rk) { if(l==r&&sum[k]==rk) return l; int mid=(l+r)>>1; int rtn; if(sum[k<<1]>=rk) rtn=qry(k<<1,l,mid,rk); else rtn=qry(k<<1|1,mid+1,r,rk-sum[k<<1]); return rtn; } bool cmp(Q a,Q b) { if(a.l!=b.l) return a.l<b.l; return a.r<b.r; } int main() { n=read();m=read(); for(int i=1;i<=n;i++) { be[i]=read();ae[i]=be[i]; } sort(ae+1,ae+1+n); t=unique(ae+1,ae+1+n)-ae-1; for(int i=1;i<=n;i++) be[i]=lower_bound(be[i]); for(int i=1;i<=m;i++)//丑陋的手写离散化 q[i].l=read(),q[i].r=read(),q[i].k=read(),q[i].id=i; sort(q+1,q+m+1,cmp); for(int i=1;i<=m;i++) { while(r<q[i].r) modi(1,1,t,be[++r],1); while(l<q[i].l) modi(1,1,t,be[l++],-1); //注意是l++,不是++l ans[q[i].id]=qry(1,1,t,q[i].k); } for(int i=1;i<=m;i++) printf("%d\n",ae[ans[i]]);//记得在离散化后还原回去 }