zoukankan      html  css  js  c++  java
  • 【BZOJ3196】Tyvj 1730 二逼平衡树

    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可能为负数
     
    题解
    树套树,调了好久,至今都不是很清楚为什么删除节点的时候不能直接减一而必须先....说不清楚了,在代码里体现吧
      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<iostream>
      4 using namespace std;
      5 const int inf=100000000,N=3000001,M=200001;
      6 int num[N],rnd[N],size[N],ls[N],rs[N],root[M],w[N],a[M];
      7 int sz,n,m,opt,l,r;
      8 void updata(int k){size[k]=size[ls[k]]+size[rs[k]]+w[k];}
      9 void rturn(int &k){int t=ls[k];ls[k]=rs[t];rs[t]=k;size[t]=size[k];updata(k);k=t;}
     10 void lturn(int &k){int t=rs[k];rs[k]=ls[t];ls[t]=k;size[t]=size[k];updata(k);k=t;}
     11 void insert(int &k,int x){
     12     if (!k){
     13         k=++sz;num[k]=x;rnd[k]=rand();size[k]=w[k]=1;return;
     14     }
     15     size[k]++;
     16     if (x==num[k]) {w[k]++;return;}
     17     if (x<num[k]) {insert(ls[k],x);if (rnd[ls[k]]<rnd[k]) rturn(k);}
     18     if (x>num[k]) {insert(rs[k],x);if (rnd[rs[k]]<rnd[k]) lturn(k);}
     19 }
     20  
     21 void del(int &k,int x){
     22     if (!k) return;
     23     if (num[k]==x){
     24         if (w[k]>1){w[k]--;size[k]--;return;}//就是这里,不知道为什么不是在前面直接size[k]--
     25         if(ls[k]*rs[k]==0){k=ls[k]+rs[k]; return;}
     26         if (rnd[ls[k]]<rnd[rs[k]])rturn(k),del(k,x);
     27         else lturn(k),del(k,x);
     28     }
     29     else if (num[k]>x) del(ls[k],x),size[k]--;else del(rs[k],x),size[k]--;
     30 }
     31  
     32 void change(int pos,int x){
     33     int k=1,l=1,r=n,mid=(l+r)>>1;
     34     while (l!=r){
     35         mid=(l+r)>>1;
     36         del(root[k],a[pos]);
     37         insert(root[k],x);
     38         if (mid>=pos)k=k<<1,r=mid;
     39         else k=k<<1|1,l=mid+1;
     40     }
     41     mid=(l+r)>>1;
     42     del(root[k],a[pos]);
     43     insert(root[k],x);    
     44 }
     45  
     46 int solve_rank(int k,int x){
     47     if (!k) return 0;
     48     int l=ls[k],r=rs[k];
     49     if (num[k]==x) return size[l];
     50     else if (num[k]>x) return solve_rank(l,x);
     51     else return solve_rank(r,x)+size[l]+w[k];
     52 }
     53  
     54 int get_rank(int k,int l,int r,int L,int R,int x){
     55     if (l==L&&r==R) return (solve_rank(root[k],x));
     56     int mid=(l+r)>>1;
     57     if (R<=mid) return get_rank(k<<1,l,mid,L,R,x);
     58     else if (L>mid) return get_rank(k<<1|1,mid+1,r,L,R,x);
     59     else return get_rank(k<<1,l,mid,L,mid,x)+get_rank(k<<1|1,mid+1,r,mid+1,R,x);
     60 }
     61  
     62 void build(int x,int y){
     63     int l=1,r=n,k=1,mid=(l+r)>>1;
     64     while(l!=r){
     65         insert(root[k],y);
     66         if (mid>=x) r=mid,mid=(l+r)>>1,k=k<<1;
     67         else l=mid+1,mid=(l+r)>>1,k=k<<1|1;
     68     }
     69     insert(root[k],y);
     70 }
     71  
     72 int get_num(int x,int y,int z){
     73     int l=1,r=inf,ans;
     74     while (l<=r){
     75         int mid=(l+r)>>1;
     76         int tmp=get_rank(1,1,n,x,y,mid);
     77         if (tmp<=z) ans=mid,l=mid+1;//因为有重复的数字,tmp偏小 
     78         else r=mid-1;
     79     }
     80     return ans;
     81 }
     82  
     83 int solve_pre(int k,int x){
     84     int l=ls[k],r=rs[k];
     85     if (!k) return 0;
     86     if (num[k]<x) return max(num[k],solve_pre(r,x));//这里不要顺手打上=
     87     else return solve_pre(l,x);
     88 }
     89  
     90 int get_pre(int k,int l,int r,int L,int R,int x){
     91     if (l==L&&r==R) return (solve_pre(root[k],x));
     92     int mid=(l+r)>>1;
     93     if (R<=mid) return get_pre(k<<1,l,mid,L,R,x);
     94     else if (L>mid) return get_pre(k<<1|1,mid+1,r,L,R,x);
     95     else return max(get_pre(k<<1,l,mid,L,mid,x),get_pre(k<<1|1,mid+1,r,mid+1,R,x));
     96 }
     97  
     98 int solve_after(int k,int x){
     99     int l=ls[k],r=rs[k];
    100     if (!k) return inf;
    101     if (num[k]>x) return min(num[k],solve_after(l,x));//这里不要顺手打上=*2
    102     else return solve_after(r,x);
    103 }
    104  
    105 int get_after(int k,int l,int r,int L,int R,int x){
    106     if (l==L&&r==R) return (solve_after(root[k],x));
    107     int mid=(l+r)>>1;
    108     if (R<=mid) return get_after(k<<1,l,mid,L,R,x);
    109     else if (L>mid) return get_after(k<<1|1,mid+1,r,L,R,x);
    110     else return min(get_after(k<<1|1,mid+1,r,mid+1,R,x),get_after(k<<1,l,mid,L,mid,x));
    111 }
    112  
    113 int main(){
    114     freopen("sj.txt","r",stdin);
    115     freopen("me.txt","w",stdout);
    116     int k;
    117     scanf("%d%d",&n,&m);
    118     for (int i=1;i<=n;i++){scanf("%d",&a[i]);build(i,a[i]);}
    119     for (int i=1;i<=m;i++){
    120         scanf("%d%d%d",&opt,&l,&r);
    121         if (opt!=3)scanf("%d",&k);
    122         switch(opt){
    123             case 1:printf("%d
    ",get_rank(1,1,n,l,r,k)+1);break;
    124             case 2:printf("%d
    ",get_num(l,r,k-1));break;
    125             case 3:change(l,r);a[l]=r;break;
    126             case 4:printf("%d
    ",get_pre(1,1,n,l,r,k));break;
    127             case 5:printf("%d
    ",get_after(1,1,n,l,r,k));break;
    128         }
    129     }
    130 }
  • 相关阅读:
    php中的_GET和_POST
    CSS中的特殊符号
    Nginx简介
    php获得时间
    php中定义类
    AcWing 803. 区间合并
    AcWing 826. 单链表
    AcWing 2816. 判断子序列
    AcWing 790. 数的三次方根
    AcWing 802. 区间和
  • 原文地址:https://www.cnblogs.com/wuminyan/p/5152475.html
Copyright © 2011-2022 走看看