玲珑杯round #20 E(主席树)

造物主的戒律,空气,变成数据结构!
于是空气变成了数据结构~
给你一个序列,每次查询区间中小于等于x的所有数字里面第k1k1小的值以及大于x的所有数字里面第k2k2小的值,如果不存在,输出-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;
}




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值