1 条题解
-
0
自动搬运
来自洛谷,原作者为

communist
Who Dare Wins !搬运于
2025-08-24 21:36:12,当前版本为作者最后更新于2018-04-10 08:35:07,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
楼下各位大佬都用的排序和杨颙大定理,蒟蒻的我怎么也不会做(瑟瑟发抖),那么,就来一发主席树吧。
我们知道线段树可以维护区间,平衡树可以维护值域
那么,我们可以用线段树套平衡树来解决这个区间值域的问题
线段树套平衡树~~(令人窒息的操作)~~
好在权值线段树也可以维护值域,
我们只要建n棵线段树维护前缀和,然后作差就好
考虑空间限制,我们需要让这些线段树共用一些节点,再搞一搞离散化,
其实这题的数据范围不用一颗主席树华丽登场
时间复杂度O(nlogn),空间复杂度O(nlogn)
上代码:
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; const int maxn=5010; struct tree{ int v,ls,rs; }a[15*maxn]; int n,m,rt[maxn],cnt,mp[maxn],v[maxn],out[maxn]; void insert(int pre,int cur,int p,int l,int r) //插入 { if(l==r) { a[cur].v=a[pre].v+1; return; } int m=(l+r)>>1; if(p<=m) { a[cur].ls=++cnt; //新建节点 a[cur].rs=a[pre].rs; //共用节点 insert(a[pre].ls,a[cur].ls,p,l,m); } else { a[cur].rs=++cnt; a[cur].ls=a[pre].ls; insert(a[pre].rs,a[cur].rs,p,m+1,r); } a[cur].v=a[a[cur].ls].v+a[a[cur].rs].v; //push up } int kth(int x,int y,int k,int l,int r) //查询k小值 { if(l==r) return l; int m=(l+r)>>1; int num=a[a[y].ls].v-a[a[x].ls].v; //前缀和 if(num>=k) //第k小在左子树 return kth(a[x].ls,a[y].ls,k,l,m); else //在右子树 return kth(a[x].rs,a[y].rs,k-num,m+1,r); } int main() { cin>>n; for(int i=1;i<=n;i++) { scanf("%d",&v[i]); mp[i]=v[i]; } sort(mp+1,mp+n+1); //特色离散化 cin>>m; for(int i=1;i<=n;i++) { v[i]=lower_bound(mp+1,mp+n+1,v[i])-mp; out[v[i]]=i; rt[i]=++cnt; insert(rt[i-1],rt[i],v[i],1,n); } for(int i=1;i<=m;i++) { int x,y,k; scanf("%d%d%d",&x,&y,&k); printf("%d\n",out[kth(rt[x-1],rt[y],k,1,n)]); } return 0; }
- 1
信息
- ID
- 1263
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 3
- 标签
- (无)
- 递交数
- 0
- 已通过
- 0
- 上传者