洛谷P1533 可怜的狗狗题解
本题可以使用权值线段树+离散化+二分解答
首先观察题目,题目要求i-j区间之内的第k大的树
所以我们可以用权值线段树,但是权值线段树只能在查找全局最大值,本题要求i-j区间的最大值
所以我们考虑使用莫队算法,因为这道题我们看出可以离线查询,对每个询问进行查询记录
另外这题数据大,所以使用离散化,具体注释看代码
#include<bits/stdc++.h> #define N 300005 using namespace std; int m,n,k; int a[N],b[N],u[N]; int pos[N]; int ans[N]; struct MM{ int l,r,s; }tr[N<<2]; struct node{ int l,r; int k; int id; }q[N]; void build(int u,int L,int R){ tr[u].l=L; tr[u].r=R; if(L==R) return; int mid=(L+R)>>1; build(u<<1,L,mid); build(u<<1|1,mid+1,R); } bool cmp(node a,node b){ if(pos[a.l]==pos[b.l]) return a.r<b.r; return pos[a.l]<pos[b.l]; } inline void modify(int u,int t,int k){ //区间更改操作,找到我们需要修改的位置,单点修改 if(tr[u].l==tr[u].r){ tr[u].s+=k; return; } int mid=(tr[u].l+tr[u].r)>>1; if(t<=mid) modify(u<<1,t,k); else modify(u<<1|1,t,k); tr[u].s=tr[u<<1].s+tr[u<<1|1].s; } inline int query(int u,int t){ //查询k小数,加入小于等于左边区间,就去左边区间找,否则去右边 if(tr[u].l==tr[u].r) return tr[u].l; if(t<=tr[u<<1].s) return query(u<<1,t); else return query(u<<1|1,t-tr[u<<1].s); //注意减去左边区间的值,因为右边区间不包括左边的值 } int main(){ cin>>n>>m; int block=sqrt(n); //分块 for(int i=1;i<=n;i++){ cin>>a[i]; pos[i]=(i-1)/block+1; b[i]=a[i]; } for(int i=1;i<=m;i++){ cin>>q[i].l>>q[i].r>>q[i].k; q[i].id=i; } sort(q+1,q+1+m,cmp); sort(b+1,b+n+1); int s=unique(b+1,b+n+1)-(b+1); //离散化模板 build(1,1,s); int l=1; int r=0; int i; for(i=1;i<=m;i++){ //莫队算法,本题莫队的add和sub函数可以用线段树的更新操作替代 while(q[i].l<l){ int st=lower_bound(b+1,b+s+1,a[--l])-b; modify(1,st,1); } while(q[i].l>l){ int st=lower_bound(b+1,b+s+1,a[l++])-b; modify(1,st,-1); } while(q[i].r>r){ int st=lower_bound(b+1,b+s+1,a[++r])-b; modify(1,st,1); } while(q[i].r<r){ int st=lower_bound(b+1,b+s+1,a[r--])-b; modify(1,st,-1); } ans[q[i].id]=b[query(1,q[i].k)]; } for(i=1;i<=m;i++) cout<<ans[i]<<endl; return 0; }
没有人不辛苦,只有人不喊疼