区间第k大(版本1)POJ2104
Description
给定一个长度为n的序列,m个询问,每个询问的形式为:L,r,k表示在[L,r]间中的第k大元素。
Input
第1行:2个数,n,m表示序列的长度和询问的个数
第2行:n个数,表示n个数的大小
第3-m+2行:每行3个数,L,r,k表示询问在[L,r]区间内第k小的元素
第2行:n个数,表示n个数的大小
第3-m+2行:每行3个数,L,r,k表示询问在[L,r]区间内第k小的元素
Output
对于每个询问,输出答案。
Sample Input
7 2
1 5 2 6 3 7 4
1 5 3
2 7 1
Sample Output
3
2
Hint
【数据范围】
对于100%的数据,n<=100000, m<=100000,1<=L<=r<=n, 1<=k<=r-L+1
对于100%的数据,n<=100000, m<=100000,1<=L<=r<=n, 1<=k<=r-L+1
Solution
一道解法多种多样的区间模板题目。树套树,主席树,划分树,整体二分什么的都可以。。。
蒟蒻今天尝试的是主席树。
我们将一个区间变成n个森林,每一次都添加相应的点计入一颗新的权值线段树。我们查询[L,R]的区间第k大时,用第R个节点对应的树减去第L-1个节点对应的树,就得到了针对[L,R]区间的一颗线段树,然后就是用权值线段树的计数来统计第k大了。
CODE
时间吊打蒟蒻之前写的树套树。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=100005;
inline int read(){
char c;int rec=0;
while((c=getchar())<'0'||c>'9');
while(c>='0'&&c<='9')rec=rec*10+c-'0',c=getchar();
return rec;
}
struct Persistent_Segtree{int F,s[2],L,R,sum;}tree[20*N];
struct Node{int id,val;}a[N];
int n,m,cnt=0;
int root[20*N];
inline int Build(int L,int R){
int mid=(L+R)>>1,p=++cnt;
tree[p].L=L;tree[p].R=R;tree[p].sum=0;
if(L==R)return p;
tree[p].s[0]=Build(L,mid);tree[p].s[1]=Build(mid+1,R);
return p;
}
inline void Inherit(int v,int pre,int val){tree[v].sum=tree[pre].sum+val;
tree[v].s[0]=tree[pre].s[0];tree[v].s[1]=tree[pre].s[1];
tree[v].L=tree[pre].L;tree[v].R=tree[pre].R;return ;
}
inline int New_Edition(int pre,int v,int val){
int p=++cnt;Inherit(p,pre,val);
if(tree[p].L==v&&tree[p].R==v)return p;
int mid=(tree[p].L+tree[p].R)>>1;
tree[p].s[v>mid]=New_Edition(tree[pre].s[v>mid],v,val);
return p;
}
inline void Ask(int p,int q,int pos){
if(tree[p].L==tree[p].R){cout<<a[tree[p].L].val<<'\n';return ;}
int t=tree[tree[p].s[0]].sum-tree[tree[q].s[0]].sum;
Ask(tree[p].s[pos>t],tree[q].s[pos>t],pos-t*(pos>t));
}
inline bool cmp(Node x,Node y){return x.val<y.val;}
int main(){
n=read();m=read();
int i,x,y,k;
root[0]=Build(1,n);
for(i=1;i<=n;i++)a[i].val=read(),a[i].id=i;
sort(a+1,a+1+n,cmp);for(i=1;i<=n;i++)root[a[i].id]=i;
for(i=1;i<=n;i++)root[i]=New_Edition(root[i-1],root[i],1);
for(i=1;i<=m;i++)x=read(),y=read(),k=read(),Ask(root[y],root[x-1],k);
return 0;
}