造物主的戒律,空气,变成数据结构!
于是空气变成了数据结构~
给你一个序列,每次查询区间中小于等于x的所有数字里面第k1小的值以及大于x的所有数字里面第k2小的值,如果不存在,输出-1
每次输出两个数,对于每个数如果不存在,则单独输出-1
INPUT
第一行两个数n,m第二行n个数表示序列a后面m行每行五个数l,r,x,k1,k2
OUTPUT
对于每个查询输出答案
SAMPLE INPUT
5 51 2 3 4 51 5 3 1 22 5 2 1 32 3 3 3 33 3 3 3 33 3 3 3 3
SAMPLE OUTPUT
1 52 5-1 -1-1 -1-1 -1
解题思路:其实我们只需要找出区间有多少个数小于等于x就行,这个很好找,我们可以用主席树解决,直接在树上跑就行,根据x值得大小和H[mid]值的大小关系决定下一步走左子树还是右子树,中间记录一下个数就行。然后就行查询区间第k小问题了。
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e5 + 10;
int n, m;
int M;
int cnt;
struct node{
int L, R;//分别指向左右子树
int sum;//该节点对应区间数的个数
node(){
sum = 0;
}
}Tree[maxn * 20];
int H[maxn];//原数组排序之后的数组
int a[maxn];
int T[maxn];
void init1()
{
cnt = 0;
sort(H, H + M);
M = unique(H, H + M) - H;
}
int Hash(int x)
{
return lower_bound(H, H + M, x) - H;
}
int build(int l, int r)//建立一棵空树T[0]
{
int f = cnt++;
Tree[f].sum = 0;
if(l == r) return f;
int mid = (l + r)>>1;
Tree[f].L = build(l, mid);
Tree[f].R = build(mid + 1, r);
return f;
}
int insert(int pa, int x, int value, int l, int r)
{
int now = cnt++;
Tree[now].sum = Tree[pa].sum + value;
if(l == r) return now;
int mid = (l + r)>>1;
if(x <= mid)
{
Tree[now].R = Tree[pa].R;
Tree[now].L = insert(Tree[pa].L, x, value, l, mid);
}
else
{
Tree[now].L = Tree[pa].L;
Tree[now].R = insert(Tree[pa].R, x, value, mid + 1, r);
}
return now;
}
int query(int i, int j, int k, int l, int r)
{
int d = Tree[Tree[j].L].sum - Tree[Tree[i].L].sum;
if(l == r) return l;
int mid = (l + r)>>1;
if(k <= d) return query(Tree[i].L, Tree[j].L, k, l, mid);
else return query(Tree[i].R, Tree[j].R, k - d, mid + 1, r);
}
int solve(int i, int j, int x, int l, int r)//l, r中有多少比小于等于x的值
{
int d = Tree[Tree[j].L].sum - Tree[Tree[i].L].sum;
if(l == r)
{
if(H[l] <= x) return Tree[j].sum - Tree[i].sum;
else return 0;
}
int mid = (l + r)>>1;
if(x > H[mid]) return (d + solve(Tree[i].R, Tree[j].R, x, mid + 1, r));
else return solve(Tree[i].L, Tree[j].L, x, l, mid);
}
void debug()
{
srand(time(NULL)) ;
for(int i = 1; i <= 10; i++)
{
int ran1 = rand() % 6 + 1;
int ran2 = rand() % 6 + 1;
if(ran1 > ran2) swap(ran1, ran2);
int k = rand() % (ran2 - ran1) + 1;
printf("l == %d r == %d k == %d\n", ran1, ran2, k);
printf("rank[k] == %d\n", H[query(T[ran1 - 1], T[ran2], k, 0, M - 1)]);
}
}
int main()
{
//freopen("C:\\Users\\creator\\Desktop\\in.txt","r",stdin) ;
//freopen("C:\\Users\\creator\\Desktop\\out.txt","w",stdout) ;
scanf("%d%d", &n, &m);
M = 0;
for(int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
H[M++] = a[i];
}
init1();
//进行离散化
T[0] = build(0, M - 1);
for(int i = 1; i <= n; i++)
{
T[i] = insert(T[i - 1], Hash(a[i]), 1, 0, M - 1);
}
int left, right, x, k1, k2;
//debug();
for(int i = 1; i <= m; i++)
{
scanf("%d%d%d%d%d", &left, &right, &x, &k1, &k2);
int num = solve(T[left - 1], T[right], x, 0, M - 1);
int dis = right - left + 1 - num;
int re1, re2;
if(num < k1)
{
re1 = -1;
if(dis < k2) re2 = -1;
else re2 = H[query(T[left - 1], T[right], num + k2, 0, M - 1)];
}
else
{
re1 = H[query(T[left - 1], T[right], k1, 0, M - 1)];
if(dis < k2) re2 = -1;
else re2 = H[query(T[left - 1], T[right], num + k2, 0, M - 1)];
}
printf("%d %d\n", re1, re2);
}
return 0;
}