2018年东北农业大学春季校赛 L wyh的天鹅【离散化+二分+线段树lglg||线段树lg||主席树lg】

链接:https://www.nowcoder.com/acm/contest/93/L
来源:牛客网

时间限制:C/C++ 3秒,其他语言6秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
你们wyh学长小时候住在河边,因为周围的生态环境非常好,所以经常会有天鹅浮在湖面上,每只天鹅都长得不一样,它们偶尔排成一排,偶尔分散开,偶尔也会去其他河畔,wyh学长为了统计它们的个数,编了一个程序赋予它们一个“萌”值,但是这些天鹅很不听话,一会儿会从别的地方游过来一两只,一会儿又会在统计过程中游走一两只,现在请你帮他完成统计任务。

输入描述:
共有T(T<=10)组数据,每组数据第一行为两个数 N, M (N,M <= 500000),代表有N只天鹅和M次操作,接下来一行是N个数字,下面M行首先会输入一个字符串S,接着会有三类操作,如果S是“insert”,接着输入一个正整数a,代表插入一只“萌”值为a的天鹅,如果S是“delete”,接着输入一个正整数a,代表删除一只“萌”值为a的天鹅,如果S是“query”,接着输入一个正整数k,代表查询“萌”值第k大的天鹅。
萌值为[1,1000000000],并且保证一定存在第k大
输出描述:
对应每次询问,输出询问结果。
示例1
输入
1
5 4
6 4 2 9 1
query 2
insert 7
delete 6
query 2
输出
6
7

分析:因为询问的区间只有一个,所以不需要主席树也可以解决。
因为所有的数字种类不会超过1e6,所以可以用离散化来映射。

双lglg版本:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
#define ll long long int
#define INF 0x3f3f3f3f
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
const int maxn = 1e6 + 10;
int Sum[maxn << 2];
int Add[maxn << 2];
int A[maxn], n;
int B[maxn];
int C[maxn];
struct node {
    int q, x;
}a[maxn];
void pushup(int rt) {
    Sum[rt] = Sum[rt << 1] + Sum[rt << 1 | 1];
}
void build(int l, int r, int rt) {
    if (l == r) { Sum[rt] = 0; return; }
    int m = (l + r) >> 1;
    build(l, m, rt << 1);
    build(m + 1, r, rt << 1 | 1);
    pushup(rt);
}
void update(int L, int C, int l, int r, int rt) {//A[L]+=C;
    if (l == r) {
        Sum[rt] += C; return;
    }
    int m = (l + r) >> 1;
    if (L <= m) update(L, C, l, m, rt << 1);
    else update(L, C, m + 1, r, rt << 1 | 1);
    pushup(rt);
}
int query(int L, int R, int l, int r, int rt) {
    if (L <= l && r <= R) {
        return Sum[rt];
    }
    int m = (l + r) >> 1;
    int ans = 0;
    if (L <= m) ans += query(L, R, l, m, rt << 1);
    if (R > m) ans += query(L, R, m + 1, r, rt << 1 | 1);
    return ans;
}
int main()
{
    int T;
    scanf("%d", &T);
    while (T--) {
        int n, m;
        scanf("%d%d", &n, &m);
        char s[20]; int j = n;
        for (int i = 1; i <= n; i++) {
            scanf("%d", &A[i]); C[i] = A[i];
        }
        for (int i = 1; i <= m; i++) {
            scanf("%s", s); scanf("%d", &a[i].x);
            if (s[0] == 'q') {
                a[i].q = 0;
            }
            else if (s[0] == 'i') {
                a[i].q = 1;
                A[++j] = a[i].x;
            }
            else if (s[0] == 'd') {
                a[i].q = 2;
            }
        }
        sort(A + 1, A + 1 + j); sort(C + 1, C + 1 + n);
        memset(B, 0, sizeof B); A[0] = INF; int sz = 0;


        for (int i = 1; i <= j; i++) {
            if (A[i] != A[i - 1]) B[++sz] = A[i];
        }


    /*  for (int i = 1; i <= sz; i++) {
            cout << B[i] << " ";
        }
        cout << endl;
*/
        memset(A, 0, sizeof A);
        build(1, sz, 1);
        for (int i = 1; i <= n; i++) {
            int d = lower_bound(B + 1, B + sz + 1, C[i]) - B;
            //cout << C[i] << " !!! " << d << endl;
            update(d, 1, 1, sz, 1);
        }
        for (int i = 1; i <= m; i++)
        {
            if (a[i].q == 0) {
                //int d=lower_bound(1,sz,a[i].x)
                int l = 1, r = sz; int mid;
                int ans;
                while (l <= r) {
                    mid = (l + r) >> 1;
                    if (query(mid, sz, 1, sz, 1) >= a[i].x) {
                        ans = mid;
                        l = mid + 1;
                    }
                    else {
                        r = mid - 1;
                    }
                }
                printf("%d\n", B[ans]);
            }
            else if (a[i].q == 1) {
                int d = lower_bound(B + 1, B + sz + 1, a[i].x) - B;
                update(d, 1, 1, sz, 1);
            }
            else if (a[i].q == 2) {
                int d = lower_bound(B + 1, B + sz + 1, a[i].x) - B;
                update(d, -1, 1, sz, 1);
            }
        }
    }
    return 0;
}

单lg版本:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
#define ll long long int
#define INF 0x3f3f3f3f
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
const int maxn = 1e6 + 10;
int Sum[maxn << 2];
int Add[maxn << 2];
int A[maxn], n;
int B[maxn];
int C[maxn];
struct node {
    int q, x;
}a[maxn];
void pushup(int rt) {
    Sum[rt] = Sum[rt << 1] + Sum[rt << 1 | 1];
}
void build(int l, int r, int rt) {
    if (l == r) { Sum[rt] = 0; return; }
    int m = (l + r) >> 1;
    build(l, m, rt << 1);
    build(m + 1, r, rt << 1 | 1);
    pushup(rt);
}
void update(int L, int C, int l, int r, int rt) {//A[L]+=C;
    if (l == r) {
        Sum[rt] += C; return;
    }
    int m = (l + r) >> 1;
    if (L <= m) update(L, C, l, m, rt << 1);
    else update(L, C, m + 1, r, rt << 1 | 1);
    pushup(rt);
}
int query(int L, int R, int l, int r, int rt) {
    if (L <= l && r <= R) {
        return Sum[rt];
    }
    int m = (l + r) >> 1;
    int ans = 0;
    if (L <= m) ans += query(L, R, l, m, rt << 1);
    if (R > m) ans += query(L, R, m + 1, r, rt << 1 | 1);
    return ans;
}
int Q(int l, int r, int rt, int x) {
    // (x <= 0) return rt;
    if (l == r) return l;
    int mid = (l + r) >> 1;
    if (Sum[rt << 1 | 1] >= x)
        return Q(mid+1, r, rt << 1 | 1, x);
    else
        return Q(l, mid, rt << 1, x - Sum[rt << 1 | 1]);
}
int main()
{
    //cout << (5 << 1 | 1) << endl;
    int T;
    scanf("%d", &T);
    while (T--) {
        int n, m;
        scanf("%d%d", &n, &m);
        char s[20]; int j = n;
        for (int i = 1; i <= n; i++) {
            scanf("%d", &A[i]); C[i] = A[i];
        }
        for (int i = 1; i <= m; i++) {
            scanf("%s", s); scanf("%d", &a[i].x);
            if (s[0] == 'q') {
                a[i].q = 0;
            }
            else if (s[0] == 'i') {
                a[i].q = 1;
                A[++j] = a[i].x;
            }
            else if (s[0] == 'd') {
                a[i].q = 2;
            }
        }
        sort(A + 1, A + 1 + j); sort(C + 1, C + 1 + n);
        memset(B, 0, sizeof B); A[0] = INF; int sz = 0;


        for (int i = 1; i <= j; i++) {
            if (A[i] != A[i - 1]) B[++sz] = A[i];
        }


        /*  for (int i = 1; i <= sz; i++) {
                cout << B[i] << " ";
            }
            cout << endl;
    */
        memset(A, 0, sizeof A);
        build(1, sz, 1);
        for (int i = 1; i <= n; i++) {
            int d = lower_bound(B + 1, B + sz + 1, C[i]) - B;
            //cout << C[i] << " !!! " << d << endl;
            update(d, 1, 1, sz, 1);
        }
        for (int i = 1; i <= m; i++)
        {
            if (a[i].q == 0) {
                int ans = Q(1, sz, 1, a[i].x);
                printf("%d\n", B[ans]);
            }
            else if (a[i].q == 1) {
                int d = lower_bound(B + 1, B + sz + 1, a[i].x) - B;
                update(d, 1, 1, sz, 1);
            }
            else if (a[i].q == 2) {
                int d = lower_bound(B + 1, B + sz + 1, a[i].x) - B;
                update(d, -1, 1, sz, 1);
            }
        }
    }
    return 0;
}

主席树版本:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值