洛谷 P1533 可怜的狗狗

洛谷 P1533 可怜的狗狗

Description

  • 小卡家有N只狗,由于品种、年龄不同,每一只狗都有一个不同的漂亮值。漂亮值与漂亮的程度成反比(漂亮值越低越漂亮),吃饭时,狗狗们会按顺序站成一排等着主人给食物。

    可是嘉嘉真的很懒,他才不肯喂这么多狗呢,这多浪费时间啊,于是他每次就只给第i只到第j只狗中第k漂亮的狗狗喂食(好狠心的人啊)。而且为了保证某一只狗狗不会被喂太多次,他喂的每个区间(i,j)不互相包含。

Input

  • 第一行输入两个数n,m,你可以假设n<300001 并且 m<50001;m表示他喂了m次。

    第二行n个整数,表示第i只狗的漂亮值为ai。

    接下来m行,每行3个整数i,j,k表示这次喂食喂第i到第j只狗中第k漂亮的狗的漂亮值。

Output

  • M行,每行一个整数,表示每一次喂的那只狗漂亮值为多少。

Sample Input

7 2
1 5 2 6 3 7 4
1 5 3
2 7 1

Sample Output

3

2

题解:

  • 平衡树。
  • 首先一说这题解法很多,莫队、主席树、划分树、线段树、平衡树。
  • 这题用平衡树还是比较巧妙的。观察到题目中有这么一个性质:每个区间(i,j)不互相包含。这就说明,原本下列的3种情况:(/为占位符)

//第一种

………..

///////…………

//第二种

………..

///……

//第三种

………..

////////////////// ………

  • 只会变成下列两种

//第一种

………..

///////…………

//第二种

………..

///////////////////// ………

  • 那么先离线把区间保存下来,按左端点从小到大排序。如果与上一个区间有重叠部分:就删掉上一个区间中与当前区间不重叠的部分,再加上当前新的部分。如果与上一个区间没有重叠部分,就删掉上一个区间,添加当前区间。这样操作就可以得到当前区间。
  • 有了这样的性质,每个位置的元素至多被删除/添加一次,复杂度就是O(nlogn),完全可以接受。
#include <iostream>
#include <cstdio>
#include <algorithm>
#define N 300005
#define M 50005
#define inf 0x7fffffff
using namespace std;

struct T {int l, r, val, dat, cnt, size;} t[N];
struct B {int l, r, k, id;} b[M];
int n, m, root, tot;
int a[N], ans[M];

int read()
{
    int x = 0, f = 1; char c = getchar();
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar();}
    return x *= f;
}

bool cmp(B x, B y)
{
    if(x.l == y.l) return x.r < y.r;
    return x.l < y.l;
}

void up(int p) {t[p].size = t[t[p].l].size + t[t[p].r].size + t[p].cnt;}

int New(int val)
{
    t[++tot].val = val, t[tot].dat = rand();
    t[tot].size = t[tot].cnt = 1;
    return tot;
}

void zig(int &y)
{
    int x = t[y].l;
    t[y].l = t[x].r, t[x].r = y, y = x;
    up(t[y].r), up(y);
}

void zag(int &x)
{
    int y = t[x].r;
    t[x].r = t[y].l, t[y].l = x, x = y;
    up(t[x].l), up(x);
}

void insert(int &p, int val)
{
    if(!p) {p = New(val); return;}
    if(val == t[p].val) {t[p].cnt++, up(p); return;}
    if(val < t[p].val)
    {
        insert(t[p].l, val);
        if(t[t[p].l].dat > t[p].dat) zig(p);
    }
    else
    {
        insert(t[p].r, val);
        if(t[t[p].r].dat > t[p].dat) zag(p);
    }
    up(p);
}

void erase(int &p, int val)
{
    if(!p) return;
    if(val == t[p].val)
    {
        if(t[p].cnt > 1) {t[p].cnt--, up(p); return;}
        if(t[p].l || t[p].r)
        {
            if(!t[p].r || t[t[p].l].dat > t[t[p].r].dat) zig(p), erase(t[p].r, val);
            else zag(p), erase(t[p].l, val);
            up(p);
        }
        else p = 0;
        return;
    }
    val < t[p].val ? erase(t[p].l, val) : erase(t[p].r, val);
    up(p);
}

int valOfRank(int p, int rank)
{
    if(!p) return inf;
    if(t[t[p].l].size >= rank) return valOfRank(t[p].l, rank);
    if(t[t[p].l].size + t[p].cnt >= rank) return t[p].val;
    return valOfRank(t[p].r, rank - t[t[p].l].size - t[p].cnt);
}

int main()
{
    New(inf), New(-inf), root = 1, t[1].l = 2, up(1);
    cin >> n >> m;
    for(int i = 1; i <= n; i++) a[i] = read();
    for(int i = 1; i <= m; i++)
    {
        b[i].l = read(), b[i].r = read();
        b[i].k = read(), b[i].id = i;
    }
    sort(b + 1, b + 1 + m, cmp);
    for(int i = 1; i <= m; i++)
    {
        if(b[i - 1].r >= b[i].l)
        {
            for(int j = b[i - 1].l; j < b[i].l; j++) erase(root, a[j]);
            for(int j = b[i - 1].r + 1; j <= b[i].r; j++) insert(root, a[j]);
        }
        else
        {
            for(int j = b[i - 1].l; j <= b[i - 1].r; j++) erase(root, a[j]);
            for(int j = b[i].l; j <= b[i].r; j++) insert(root, a[j]);
        }
        ans[b[i].id] = valOfRank(root, b[i].k + 1);
    }
    for(int i = 1; i <= m; i++) printf("%d\n", ans[i]);
    return 0;
}
上一篇:zookeeper 启动脚本


下一篇:区间最大公约数