(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,为操作的参数 (0≤∣x∣≤109)。

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

第 1∼6 组数据:0n≤5000,m≤10000。

第 7∼10 组数据:0n≤10000,m≤100000。

第 11∼20 组数据:0n≤200000,m≤2000000。

所有数据都是随机数据。



#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\n", 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\n", t);
        }
        else if(op[0] == ‘S‘) {
            int t=suc(rt, read());
            if(t != inf) printf("%d\n", t);
        }
        else if(op[1] == ‘i‘) {
            if(rt) printf("%d\n", tr[Min(rt)].val);
        }
        else {
            if(rt) printf("%d\n", tr[Max(rt)].val);
        }
    }
    return 0;
}

//Treap

-

原文地址:https://www.cnblogs.com/de-compass/p/12145960.html

时间: 2024-10-13 08:45:09

(Updating)【区间操作数据结构例题】的相关文章

hdu 4348 To the moon(主席树区间操作)

题目链接:hdu 4348 To the moon 题意: 给你n个数,有m个操作. 1.给区间[l,r]的所有数+d,并且时间戳+1 2.询问当前时间戳的区间和. 3.询问过去时间戳t的区间和. 4.退回到时间戳t. 题解: 直接上主席树. 不过区间操作的时候push_down空间似乎不是那么够用. 所有把push_down这个操作去掉. 用一个标记记录当前这个区间的累加. 询问的时候就将这个累加传下去.(具体看代码) 最后还有退回状态t的时候可以把cnt=root[t+1], 因为后面的内存

HDU 4578 线段树区间更新(确定区间操作的优先级)

HDU 4578 线段树区间更新 操作有: 区间所有数add(c) 区间所有数mul(c) 区间所有数set(c) 查询有: 区间所有数的p次方和(p>= 1 && p <= 3) 关键是区间更新的三种操作的优先级的确定清楚set>mul>add 关键是:down和update中对区间的更新操作是一回事,可以写成函数方便编程 //#pragma warning (disable: 4786) //#pragma comment (linker, "/STA

平衡树 fhqTreap 区间操作

//Treap fhq版(不旋转) //此模板为平衡树维护区间操作的模板 //注:在区间操作中split()标准变为子树大小 #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<queue> #define INF 0x3f3f3f3f #de

COJ 0995 WZJ的数据结构(负五)区间操作

WZJ的数据结构(负五) 难度级别:C: 运行时间限制:1000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 请你设计一个数据结构,完成以下功能: 给定一个大小为N的整数组A,要求你回答执行M次操作.操作分两种: 操作1:每次操作给你l,r,v三个参数,求Al至Ar中值<=v的个数. 操作2:每次操作给你l,r,v三个参数,将Al至Ar中每个数的值+v. 输入 第一行为一个正整数N.第二行为N个整数Ai.第三行为一个正整数M.接下来M行每行4个正整数t,l,

COJ 1010 WZJ的数据结构(十) 线段树区间操作

传送门:http://oj.cnuschool.org.cn/oj/home/problem.htm?problemID=1001 WZJ的数据结构(十) 难度级别:D: 运行时间限制:3000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 请你设计一个数据结构,高效执行以下过程: #include<iostream>using namespace std;const int maxn=100010;int A[maxn];int tp,ql,qr,v;int

L - Vases and Flowers - hdu 4614(区间操作)

题意:有两种操作,第一种从A开始插花,如果有花就跳到下一个,然后输出最后一个花瓶的编号,如果花瓶不够把多余的花丢掉.操作2把区间清空 分析:很明显的线段树操作,就是插花的时候麻烦一下,需要先找出来他剩余的花瓶数,要不没办法更新. ******************************************************************* #include<algorithm>#include<stdio.h>using namespace std; #de

Codeforces 719E [斐波那契区间操作][矩阵快速幂][线段树区间更新]

/* 题意:给定一个长度为n的序列a. 两种操作: 1.给定区间l r 加上某个数x. 2.查询区间l r sigma(fib(ai)) fib代表斐波那契数列. 思路: 1.矩阵操作,由矩阵快速幂求一个fib数根据矩阵的乘法结合率,A*C+B*C=(A+B)*C; 这样可以通过线段树维护某个区间2*1矩阵的和. 2.时限卡的紧...用我的矩阵乘法板子TLE了.所以把板子里边的三重循环改成手工公式... 3.注意(a+b)%mod.这种,改成if(a+b>=mod)a+b-mod这种形式时间几乎

2014多校10(1003)hdu4973(简单线段树区间操作)

A simple simulation problem. Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 679    Accepted Submission(s): 269 Problem Description There are n types of cells in the lab, numbered from 1 to n.

poj-3468 区间操作

http://poj.org/problem?id=3468 区间求和操作 ,一个区间加操作. #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <cstdlib> #include <algorithm> #include <vector> #include <set> #include &l