bzoj 3196 (Tyvj 1730 二逼平衡树

3196: Tyvj 1730 二逼平衡树

Time Limit: 10 Sec   Memory Limit: 128 MB
Submit: 1363   Solved: 579
[ Submit][ Status][ Discuss]

Description

您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
1.查询k在区间内的排名
2.查询区间内排名为k的值
3.修改某一位值上的数值
4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)
5.查询k在区间内的后继(后继定义为大于x,且最小的数)

Input

第一行两个数 n,m 表示长度为n的有序序列和m个操作
第二行有n个数,表示有序序列
下面有m行,opt表示操作标号
若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间[l,r]的排名
若opt=2 则为操作2,之后有三个数l,r,k 表示查询区间[l,r]内排名为k的数
若opt=3 则为操作3,之后有两个数pos,k 表示将pos位置的数修改为k
若opt=4 则为操作4,之后有三个数l,r,k 表示查询区间[l,r]内k的前驱
若opt=5 则为操作5,之后有三个数l,r,k 表示查询区间[l,r]内k的后继

Output

对于操作1,2,4,5各输出一行,表示查询结果

Sample Input

9 6
4 2 2 1 9 4 0 1 1
2 1 4 3
3 4 10
2 1 4 3
1 2 5 9
4 3 9 5
5 2 8 5

Sample Output

2
4
3
4
9

HINT

1.n和m的数据范围:n,m<=50000


2.序列中每个数的数据范围:[0,1e8]


3.虽然原题没有,但事实上5操作的k可能为负数



http://www.lydsy.com/JudgeOnline/problem.php?id=3196


记原数组为a[i] i从1开始。

基本的Treap树这中平衡树结构能够查找某数的rank、先驱、后继、第k大、结点修改,复杂度分别为logn、logn、logn、logn*logn、logn。

加入了区间的思想之后,就用线段树进行统计,每个线段树结点下都挂着一颗Treap树统计该区间中的每个数。

操作1:找k在某段区间的rank,只要用线段树统计每个子区间的情况,该rank等于小于k的数的个数之和,[1,6] = [1,4]+[5,6],把这样精确覆盖的小区间依次求出。

操作2:找出rank为k的数,二分操作1的rank,找rank小于等于k的最大的数。

操作3:修改pos位置的值为k,对于所有包含pos的线段树的结点,都应该修改这个a[pos]为k,那么转换为Treap的操作,只要先统一删除a[pos]这个值,再插入k这个值就好了。

操作4:找区间[l,r]里小于k的最大的数,和操作1类似,Treap树找前驱就是从根开始往下走,边走边统计。

操作5:找区间[l,r]里大于k的最小的数,和操作4类似,比较符号和儿子都倒过来再写一遍。


#include <iostream>
#include <cstdio>
#include <cstdlib>

using namespace std;

const int N = 50001;
const int inf = 100000000;
struct Node{
    Node* ch[2];
    int r,v,s,w;//儿子 随机数 值 结点总数 次数
    void init(int v=0){
        this->v = v;
        ch[0] = ch[1] = NULL;
        r = rand();
        s = 1;
        w = 1;
    }
    bool operator <(const Node& rhs)const{
        return r<rhs.r;
    }
    int cmp(int x)const{
        if (x==v) return -1;
        return x<v ? 0 : 1;
    }

    void maintain(){
        s = w;
        if (ch[0]) s += ch[0]->s;
        if (ch[1]) s += ch[1]->s;
    }
};

Node* root[N*4]; int a[N];
Node node[N*4*16];
int tot=1;int tmp;
int n, m;

Node* newNode(int v){
    node[tot].init(v);
    return &node[tot++];
}

void rotate(Node* &o,int d){
    Node* k = o->ch[d^1]; o->ch[d^1] = k->ch[d]; k->ch[d] = o;
    o->maintain(); k->maintain(); o = k;
}

void insert(Node* &o,int num){
    if (!o)o = newNode(num);
    else{
        int d = o->cmp(num);
        if (d<0){o->w++;}
        else{
            insert(o->ch[d], num);
            if (o->ch[d] > o) rotate(o,d^1);
        }
    }
    o->maintain();
}

void build(int o,int l,int r,int x,int num){
    insert(root[o],num);
    if(l==r) return;
    int m = (l+r)>>1;
    if(x<=m) build(o<<1,l,m,x,num);
    else build(o<<1|1,m+1,r,x,num);
}

void ask_rank(Node* &o,int num){
    if (!o) return;
    else if(num == o->v) { if(o->ch[0])tmp+=o->ch[0]->s; return;}
    else if(num < o->v) ask_rank(o->ch[0], num);
    else{
        tmp += o->ch[0]? o->ch[0]->s : 0;
        tmp += o->w;
        ask_rank(o->ch[1], num);
    }
}

void get_rank(int o,int l,int r,int x,int y,int num){
    if(l==x && r==y) {
        ask_rank(root[o], num); return ;
    }
    int mid = (l+r)>>1;
    if (mid>=y) get_rank(o<<1,l,mid,x,y,num);
    else if (mid<x) get_rank(o<<1|1,mid+1,r,x,y,num);
    else{
        get_rank(o<<1,l,mid,x,mid,num);
        get_rank(o<<1|1,mid+1,r,mid+1,y,num);
    }
}

void get_index(int x, int y, int k){
    int num;
    int l = 0, r = inf, m;
    while(l<=r){
        m = (l+r)>>1;
        tmp = 1;
        get_rank(1, 1, n, x, y, m);
        if (tmp<=k){
            l = m+1;
            num = m;
        }
        else{
            r = m-1;
        }
    }
    printf("%d\n", num);
}

void del(Node* &o,int num){

    int d = o->cmp(num);
    if (d<0){
        if (o->w==1){
            if (o->ch[0] && o->ch[1]){
                int d2 = (o->ch[0]) > (o->ch[1]);
                rotate(o,d2); del(o->ch[d2], num);
            }
            else{
                if (o->ch[0]){
                    o = o->ch[0];
                }
                else if (o->ch[1]){
                    o = o->ch[1];
                }
                else{
                    o = NULL;
                }
            }
        }else{
            o->w--;
        }
    }
    else{
        del(o->ch[d], num);
    }
    if(o) o->maintain();
}

void change(int o,int l,int r,int x,int nxt,int cur){
    del(root[o],cur);
    insert(root[o],nxt);
    if(l==r) return;
    int m = (l+r)>>1;
    if(x<=m) change(o<<1,l,m,x,nxt,cur);
    else change(o<<1|1,m+1,r,x,nxt,cur);
}

void ask_before(Node* &o,int num){
    if (!o) return;
    else if (o->v < num) {
        tmp = max(o->v, tmp);
        ask_before(o->ch[1], num);
    }
    else{
        ask_before(o->ch[0], num);
    }
}

void get_before(int o,int l,int r,int x,int y,int num){
    if(l==x && r==y) {
        ask_before(root[o], num); return ;
    }
    int mid = (l+r)>>1;
    if (mid>=y) get_before(o<<1,l,mid,x,y,num);
    else if (mid<x) get_before(o<<1|1,mid+1,r,x,y,num);
    else{
        get_before(o<<1,l,mid,x,mid,num);
        get_before(o<<1|1,mid+1,r,mid+1,y,num);
    }
}

void ask_after(Node* &o,int num){
    if (!o) return;
    else if (o->v > num) {
        tmp = min(o->v, tmp);
        ask_after(o->ch[0], num);
    }
    else{
        ask_after(o->ch[1], num);
    }
}

void get_after(int o,int l,int r,int x,int y,int num){
    if(l==x && r==y) {
        ask_after(root[o], num); return ;
    }
    int mid = (l+r)>>1;
    if (mid>=y) get_after(o<<1,l,mid,x,y,num);
    else if (mid<x) get_after(o<<1|1,mid+1,r,x,y,num);
    else{
        get_after(o<<1,l,mid,x,mid,num);
        get_after(o<<1|1,mid+1,r,mid+1,y,num);
    }
}

int main()
{
    int op, l, r, k, pos;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++) build(1,1,n,i,a[i]);
    while(m--){
        scanf("%d", &op);
        if (op == 1){
            scanf("%d%d%d", &l, &r, &k);
            tmp = 1;
            get_rank(1,1,n,l,r,k);
            printf("%d\n", tmp);
        }
        else if (op == 2){
            scanf("%d%d%d", &l, &r, &k);
            get_index(l,r,k);
        }
        else if (op == 3){
            scanf("%d%d", &pos, &k);
            change(1,1,n,pos,k,a[pos]);
            a[pos] = k;
        }
        else if (op == 4){
            scanf("%d%d%d", &l, &r, &k);
            tmp = 0;
            get_before(1,1,n,l,r,k);
            printf("%d\n", tmp);
        }
        else if (op == 5){
            scanf("%d%d%d", &l, &r, &k);
            tmp = inf;
            get_after(1,1,n,l,r,k);
            printf("%d\n", tmp);
        }
    }
    return 0;
}









你可能感兴趣的:(树套树)