(Updating)区间操作数据结构例题

Posted de-compass

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(Updating)区间操作数据结构例题相关的知识,希望对你有一定的参考价值。

Description

你需要写一种数据结构,来维护一个集合 A(元素可重复),其中需要支持如下操作:

  1. Insert(A,x):向集合 A 中插入一个整数 x。

  2. Delete(A,x):删除集合 A 中值为整数 x 的元素,若有多个相同的数,只删除一个,若 x 不存则忽略。

  3. Max(A):查询集合中最大的元素,若不存在则忽略。

  4. Min(A):查询集合中最小的元素,若不存在则忽略。

  5. Find(A,x):查询整数 x 的元素是否存在,若存在输出Y,否则输出N

  6. Pred(A,x):查询求 x 的前驱(前驱定义为小于 x,且最大的数),若 x 没有前驱,则忽略。

  7. Succ(A,x):查询 x 的后继(后继定义为大于 x,且最小的数),若 x 没有后继,则忽略。

最开始,集合中已经有 n 个元素。

Input

第 1 行包含两个整数 n,m,其中 n 表示最初集合 A 中元素的个数, m 表示对集合维护和查询操作数目。

第 2 行包含 n 个整数,表示开始集合 A 中的元素 a[1]..a[n] (a[i]109)。

接下来的 m 行,每行的第一项是操作单词,分别是Insert,Delete,Max,Min,Find,PredSucc等操作,

若该操作有操作参数,则第二项为一个整数 x,为操作的参数 (0x109)。

Output

对应输入中的Max,Min,Find,PredSucc操作,每个操作输出该操作的执行结果,若要忽略这个操作,则该项没有输出。

Sample Input 1 

10 22
8 4 1 6 3 5 9 2 7 6
Insert 10
Delete 5
Min
Max
Find 6
Pred 6
Succ 8
Delete 6
Delete 1
Insert 0
Delete 10
Insert 8
Delete 3
Find 3
Succ 8
Pred 8
Max
Min
Delete 4
Delete 9
Succ 8
Pred 8

Sample Output 1

1
10
Y
4
9
N
9
7
9
0
7

Hint

第 16 组数据:0n5000,m10000。

第 710 组数据:0n10000,m100000。

第 1120 组数据:0n200000,m2000000。

所有数据都是随机数据。


 

技术图片
#include<bits/stdc++.h>
#define lc tr[p].ch[0]
#define rc tr[p].ch[1]
using namespace std;
const int maxn = 2500005, inf=0x3f3f3f3f;

int read() {
    int o=0, f=1;
    char ch;
    while(!isdigit(ch=getchar())) if(ch==-) f=-1;
    while(isdigit(ch)) o=o*10+ch-0, ch=getchar();
    return o*f;
}

struct Treap{
    int ch[2];
    int val, cnt;
    int siz, rk;
} tr[maxn];

void up(int p) { tr[p].siz = tr[lc].siz + tr[rc].siz + 1; }

void rotate(int &p, int d) {
    int son = tr[p].ch[d];
    tr[p].ch[d] = tr[son].ch[d^1];
    tr[son].ch[d^1] = p;
    up(p); up(p=son);
}

int np=0;
void insert(int &p, int x) {
    if(!p) {
        tr[p=++np] = (Treap){0, 0, x, 1, 1, rand()};
        return;
    }
    tr[p].siz++;
    if(tr[p].val == x) { tr[p].cnt++; return; }
    int d = tr[p].val < x; insert(tr[p].ch[d], x);
    if(tr[p].rk > tr[tr[p].ch[d]].rk) rotate(p, d);
}

void del(int &p, int x) {
    if(!p) return;
    if(tr[p].val == x) {
        if(tr[p].cnt > 1) {
            tr[p].siz--;
            tr[p].cnt--;
            return;
        }
        if(!lc || !rc) {
            p = lc + rc; // 利用引用更新父节点指向 
            return;
        }
        int d = tr[rc].rk < tr[lc].rk;
        rotate(p, d);
        del(p, x);
    } else {
        int d = tr[p].val < x;
        del(tr[p].ch[d], x);
        up(p);
    }
}

int find(int p, int x) {
    while(p && tr[p].val != x)
        if(tr[p].val < x) p=rc;
        else p=lc;
    return p;
}

int Max(int p) {
    while(p && rc) p=rc;
    return p;
}

int Min(int p) {
    while(p && lc) p=lc;
    return p;
}

int pred(int p, int x) {
    if(!p) return -inf;
    if(tr[p].val >= x) return pred(lc, x);
    return max(tr[p].val, pred(rc, x));
}

int suc(int p, int x) {
    if(!p) return inf;
    if(tr[p].val <= x) return suc(rc, x);
    return min(tr[p].val, suc(lc, x));
}

void prt(int p) {
    if(!p) return;
    prt(lc);
    printf("%d %d %d %d %d
", p, tr[p].val, tr[p].cnt, lc, rc);
    prt(rc);
}

int main() {
    int n=read(), m=read(), rt=0;
    while(n--) insert(rt, read());
    while(m--) {
        char op[10];
        scanf("%s", op);
        if(op[0] == I) insert(rt, read());
        else if(op[0] == D) del(rt, read());
        else if(op[0] == F) puts( find(rt, read())? "Y" : "N");
        else if(op[0] == P) {
            int t=pred(rt, read());
            if(t != -inf) printf("%d
", t);
        }
        else if(op[0] == S) {
            int t=suc(rt, read());
            if(t != inf) printf("%d
", t);
        }
        else if(op[1] == i) {
            if(rt) printf("%d
", tr[Min(rt)].val);
        }
        else {
            if(rt) printf("%d
", tr[Max(rt)].val);
        }
    }
    return 0;
}
//Treap

 

-

以上是关于(Updating)区间操作数据结构例题的主要内容,如果未能解决你的问题,请参考以下文章

线段树详解

ybtoj线段树课堂过关例题1求区间和

luoguP3374ybtoj树状数组例题1单点修改区间查询

1423:例题2种树

线段树分治总结

ybtoj树状数组课堂过关二维树状数组 例题5单点修改区间查询