zoukankan      html  css  js  c++  java
  • 洛谷 P3380 【模板】二逼平衡树(树套树)-线段树套splay

    P3380 【模板】二逼平衡树(树套树)

    题目描述

    您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:

    1. 查询k在区间内的排名

    2. 查询区间内排名为k的值

    3. 修改某一位值上的数值

    4. 查询k在区间内的前驱(前驱定义为严格小于x,且最大的数,若不存在输出-2147483647)

    5. 查询k在区间内的后继(后继定义为严格大于x,且最小的数,若不存在输出2147483647)

    注意上面两条要求和tyvj或者bzoj不一样,请注意

    输入输出格式

    输入格式:

    第一行两个数 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的后继

    输出格式:

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

    输入输出样例

    输入样例#1: 复制
    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
    输出样例#1: 复制
    2
    4
    3
    4
    9

    说明

    时空限制:2s,128M

    n,m leq 5cdot {10}^4n,m5104 保证有序序列所有值在任何时刻满足 [0, {10} ^8][0,108]

    题目来源:bzoj3196 / Tyvj1730 二逼平衡树,在此鸣谢

    此数据为洛谷原创。(特别提醒:此数据不保证操作4、5一定存在,故请务必考虑不存在的情况)

    思路:把普通平衡树代码中rtrt改成rt[pos],写一个线段树,线段树每个点都挂一个splay。

    数据范围开22倍正好能过,写的时候老是RE和MLE,最后就是试数据范围过了。。。

    代码(自己的板子没写过,百度的其他人的板子):

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 const int N=5e4*22,inf=2147483647;
      4 #define lc ch[0]
      5 #define rc ch[1]
      6 int sz[N],fa[N],cnt[N],a[N],ans,mid,l,r,ll,rr,k,rt[N],tot,val[N],ch[2][N],n,m,i,opt;
      7 inline char gc(){
      8     static char buf[100000],*p1=buf,*p2=buf;
      9     return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
     10 }
     11 inline int rd(){
     12     int x=0,fl=1;char ch=gc();
     13     for (;ch<48||ch>57;ch=gc())if(ch=='-')fl=-1;
     14     for (;48<=ch&&ch<=57;ch=gc())x=(x<<3)+(x<<1)+(ch^48);
     15     return x*fl;
     16 }
     17 inline void wri(int a){if(a<0)a=-a,putchar('-');if(a>=10)wri(a/10);putchar(a%10|48);}
     18 inline void wln(int a){wri(a);puts("");}
     19 //---------------------------------------------------------平衡树
     20 void upd(int x){sz[x]=sz[lc[x]]+sz[rc[x]]+cnt[x];}
     21 void rot(int x){
     22     int y=fa[x],z=fa[y];bool f=x==rc[y];
     23     if (z) ch[y==rc[z]][z]=x;
     24     fa[x]=z,fa[y]=x,fa[ch[!f][x]]=y,ch[f][y]=ch[!f][x],ch[!f][x]=y;
     25     upd(y);
     26 }
     27 void splay(int pos,int x){
     28     while (fa[x]){
     29         int y=fa[x],z=fa[y];
     30         if (z) rot((y==rc[z])^(x==rc[y])?x:y);
     31         rot(x);
     32     }
     33     upd(x);
     34     rt[pos]=x;
     35 }
     36 void ins(int pos,int x){
     37     int t=rt[pos],ff=0;
     38     while (t){
     39         sz[t]++;
     40         if (x==val[t]){
     41             cnt[t]++;
     42             return;
     43         }
     44         ff=t,t=ch[x>val[t]][t];
     45     }
     46     t=++tot;
     47     ch[x>val[ff]][ff]=t;
     48     fa[t]=ff,val[t]=x,lc[t]=rc[t]=0,sz[t]=cnt[t]=1;
     49     splay(pos,t);
     50 }
     51 int find(int pos,int x){
     52     int t=rt[pos];
     53     do{
     54         if (x==val[t]) break;
     55         t=ch[x>val[t]][t];
     56     }while (1);
     57     splay(pos,t);
     58     return t;
     59 }
     60 int Rank(int pos,int x){
     61     int t=rt[pos],ret=0;
     62     while (t){
     63         if (x==val[t]) return ret+sz[lc[t]];
     64         if (x>val[t]){
     65             ret+=sz[lc[t]]+cnt[t];
     66             t=rc[t];
     67         }else t=lc[t];
     68     }
     69     return ret;
     70 }
     71 //int Max(int x){return rc[x]?Max(rc[x]):x;}
     72 int Max(int t){while (rc[t]) t=rc[t];return t;}
     73 void del(int pos,int x){
     74     x=find(pos,x);
     75     int ls=lc[x],rs=rc[x];
     76     if (--cnt[x]) return;
     77     if (!ls && !rs){//不能直接return,先清空一下
     78         int &k=rt[pos];
     79         k=fa[k]=lc[k]=rc[k]=sz[k]=cnt[k]=val[k]=0;
     80         return;
     81     }
     82     if (!ls) rt[pos]=rc[x],fa[rt[pos]]=0;
     83     else if (!rs) rt[pos]=lc[x],fa[rt[pos]]=0;
     84     else{
     85         int lson=Max(ls);swap(ls,lson);
     86         fa[lson]=0,splay(pos,ls),rc[ls]=rs,fa[rs]=ls,upd(ls);
     87     }
     88 }
     89 /*int PRE(int t,int x){
     90     if (!t) return 0;
     91     if (x<=val[t]) return PRE(lc[t],x);
     92     int tmp=PRE(rc[t],x);
     93     return tmp?tmp:t;
     94 }
     95 int pre(int pos,int x){return val[PRE(rt[pos],x)];}*/
     96 int pre(int pos,int x){
     97     int t=rt[pos];int ans=-inf;
     98     while (t)
     99         if (x>val[t]) ans=max(ans,val[t]),t=rc[t];
    100         else t=lc[t];
    101     return ans;
    102 }
    103 int nxt(int pos,int x){
    104     int t=rt[pos];int ans=inf;
    105     while (t)
    106         if (x<val[t]) ans=min(ans,val[t]),t=lc[t];
    107         else t=rc[t];
    108     return ans;
    109 }
    110 //---------------------------------------------------------线段树
    111 #define mid ((l+r)>>1)//如果没加,这个mid就变二分里的mid了
    112 void insert(int t,int l,int r,int x,int v){
    113     ins(t,v);//和下面的修改一样,我刚开始是在l==r的时候插入的
    114     if (l==r) return;
    115     if (x<=mid) insert(t<<1,l,mid,x,v);
    116     else insert(t<<1|1,mid+1,r,x,v);
    117     //函数开始的ins()作用跟update()差不多
    118 }
    119 void change(int t,int l,int r,int x,int v){
    120     del(t,a[x]),ins(t,v);//刚开始写的是del(t,v)
    121     if (l==r) return;
    122     if (x<=mid) change(t<<1,l,mid,x,v);
    123     else change(t<<1|1,mid+1,r,x,v);
    124 }
    125 int query(int t,int l,int r,int x,int y,int v){
    126     if (x<=l && r<=y) return Rank(t,v);
    127 //  if (x<=l && r<=y) return sz[lc[find(t,v)]];----会有不存在v的情况,find()会死循环
    128     int ans=0;
    129     if (x<=mid) ans+=query(t<<1,l,mid,x,y,v);
    130     if (mid<y) ans+=query(t<<1|1,mid+1,r,x,y,v);
    131     return ans;
    132 }
    133 int Prev(int t,int l,int r,int x,int y,int v){
    134     if (x<=l && r<=y) return pre(t,v);
    135     int ans=-inf;
    136     if (x<=mid) ans=max(ans,Prev(t<<1,l,mid,x,y,v));
    137     if (mid<y) ans=max(ans,Prev(t<<1|1,mid+1,r,x,y,v));
    138     return ans;
    139 }
    140 int Succ(int t,int l,int r,int x,int y,int v){
    141     if (x<=l && r<=y) return nxt(t,v);
    142     int ans=inf;
    143     if (x<=mid) ans=min(ans,Succ(t<<1,l,mid,x,y,v));
    144     if (mid<y) ans=min(ans,Succ(t<<1|1,mid+1,r,x,y,v));
    145     return ans;
    146 }
    147 #undef mid
    148 int main(){
    149     n=rd(),m=rd();
    150     for (i=1;i<=n;i++) a[i]=rd(),insert(1,1,n,i,a[i]);
    151     for (;m--;){
    152         opt=rd(),l=rd();
    153         if (opt!=3) r=rd();
    154         k=rd();
    155         if (opt==1) wln(query(1,1,n,l,r,k)+1);
    156         if (opt==2){
    157             ll=0,rr=1e8;
    158             while (ll<=rr){
    159                 mid=ll+rr>>1;
    160                 if (query(1,1,n,l,r,mid)+1<=k) ans=mid,ll=mid+1;
    161                 else rr=mid-1;
    162                 /*if (query(1,1,n,l,r,mid)+1<k) ll=mid+1;------比如查询k=1时query()+1一定>=k,会导致不断向左,输出0
    163                 else ans=mid,rr=mid-1;
    164                 其实两者本质差别是query()+1==k的时候应该向左还是向右,
    165                 如果是小于号的话,rr不断向左,query()也变小,导致答案和标程差很多*/
    166             }
    167             wln(ans);
    168         }
    169         if (opt==3) change(1,1,n,l,k),a[l]=k;//a[l]=k不能忘
    170         if (opt==4) wln(Prev(1,1,n,l,r,k));
    171         if (opt==5) wln(Succ(1,1,n,l,r,k));
    172     }
    173 }
  • 相关阅读:
    IntelliJ IDEA注册码
    linux中patch命令 -p 选项
    设备文件简介
    《算法导论》——矩阵
    《算法导论》——数论
    linux常用查看硬件设备信息命令(转载)
    netstat和telnet命令在Windows7中的用法(转载)
    c++容器使用总结(转载)
    离散数学——数论算法
    c语言中内存对齐问题
  • 原文地址:https://www.cnblogs.com/ZERO-/p/10883533.html
Copyright © 2011-2022 走看看