[bzoj 3196] 二逼平衡树

27 篇文章 0 订阅

网上各种方法都有了。。。。

去年学主席树的时候准备用树状数组套主席树水过,结果发现空间比较吃紧,就一直放在那边没敢碰。

前几天在那出来时——嗯,似乎是裸的线段树套平衡树(虽然我没有写过)……

每个线段树节点上维护一个此区间上按键值大小建立的平衡树。

操作1、直接找区间内有多少个数小于他即刻。

操作2、二分答案后就变成了操作1

操作3、一路修改下去吧。。。。

操作4、在线段树上的每一个子区间找前驱,保留最大值

操作5、在线段树上的每一个子区间找后继,保留最小值

于是就这样码下去了。。。。。

树套树也不是很难写嘛,就算难写也是很好调的。。。。

#include <cstdio>
#include <cstring>
#include <algorithm>
 
using namespace std;
const int Maxn=1000005, INF=1e8;
int fa[Maxn],size[Maxn],son[Maxn][2];
int root[Maxn],w[Maxn],a[Maxn];
int n,m,type,tot,i,ans,l,r,k;
 
void rotate(int x,int ft,int K){
  if (fa[ft]){
    if (son[fa[ft]][0]==ft)
      son[fa[ft]][0]=x;
    else son[fa[ft]][1]=x;
  }
  fa[x] = fa[ft];
   
  if (son[x][K^1]) fa[son[x][K^1]]=ft;
  son[ft][K] = son[x][K^1];
  son[x][K^1] = ft; fa[ft] = x;
  size[ft] = size[son[ft][0]] + size[son[ft][1]] + 1;
}
 
void Splay(int p,int x,int y){
  int ft, gf;
  while (fa[x]!=y){
    ft = fa[x]; gf = fa[ft];
    if (gf==y){
      if (son[ft][0]==x) rotate(x,ft,0);
      if (son[ft][1]==x) rotate(x,ft,1);
    } else
    {
      if (son[ft][0]==x && son[gf][0]==ft) rotate(ft,gf,0), rotate(x,ft,0);
      if (son[ft][1]==x && son[gf][1]==ft) rotate(ft,gf,1), rotate(x,ft,1);
      if (son[ft][0]==x && son[gf][1]==ft) rotate(x,ft,0), rotate(x,gf,1);
      if (son[ft][1]==x && son[gf][0]==ft) rotate(x,ft,1), rotate(x,gf,0);
    }
  }
  size[x] = size[son[x][0]] + size[son[x][1]] + 1;
  if (y==0) root[p] = x;
}
 
int binary(int l,int r){
  if (l>r) return 0;
  int mid = (l+r)>>1;
  son[mid][0] = binary(l,mid-1);
  son[mid][1] = binary(mid+1,r);
  if (son[mid][0]) fa[son[mid][0]]=mid;
  if (son[mid][1]) fa[son[mid][1]]=mid;
  size[mid] = size[son[mid][0]] + size[son[mid][1]] + 1;
  return mid;
}
 
int build_bin(int l,int r){
  for (int i=l;i<=r;i++)
    w[tot+i-l+1] = a[i];
  sort(w+tot+1,w+tot+(r-l+1)+1);
  int ret = binary(tot+1,tot+r-l+1);
  tot = tot+r-l+1;
  return ret;
}
 
void build_seg(int p,int l,int r){
  root[p] = build_bin(l,r);
  if (l==r) return;
  int mid = (l+r)>>1;
  build_seg(p*2+1,l,mid);
  build_seg(p*2+2,mid+1,r);
}
 
int find_rank(int p,int k){
  int t=root[p], ret=0;
  while (true){
    if (t==0) break;
    if (w[t]<k){
      ret+=size[son[t][0]]+1;
      t=son[t][1];
    } else
      t=son[t][0];
  }
  return ret;
}
 
int find_knumber_rank(int p,int l,int r,int L,int R,int k){
  if (L>r || l>R) return 0;
  if (L<=l && R>=r)
    return find_rank(p,k);
  int mid=(l+r)>>1;
  int ret1 = find_knumber_rank(p*2+1,l,mid,L,R,k);
  int ret2 = find_knumber_rank(p*2+2,mid+1,r,L,R,k);
  return ret1+ret2;
}
 
int find_pos(int p,int k){
  int t=root[p];
  while (true){
    if (t==0) break;
    if (w[t]==k) return t;
    if (w[t]>k) t=son[t][0];
      else t=son[t][1];
  }
  return 0;
}
 
void del(int p,int t){
  Splay(p,t,0);
  int L=son[t][0], R=son[t][1];
  while (son[L][1]) L=son[L][1];
  while (son[R][0]) R=son[R][0];
  if (L==0 && R==0) {root[p]=0;return;}
  if (L==0) {Splay(p,R,0);son[R][0]=0;Splay(p,R,0);return;}
  if (R==0) {Splay(p,L,0);son[L][1]=0;Splay(p,L,0);return;}
  Splay(p,L,0); Splay(p,R,L);
  son[R][0]=0; Splay(p,R,0);
}
 
void ins(int p,int d){
  int t=root[p];
  if (t==0){
    root[p]=d;
    size[d]=1;
    fa[d]=0;
    return;
  }
  while (true){
    if (w[t]>w[d]){
      if (son[t][0]==0)
        {son[t][0]=d;fa[d]=t;break;}
      else t=son[t][0];
    } else
    {
      if (son[t][1]==0)
        {son[t][1]=d;fa[d]=t;break;}
      else t=son[t][1];
    }
  }
  Splay(p,d,0);
}
 
void modify(int p,int l,int r,int pos,int k){
  int t = find_pos(p,a[pos]);
  del(p,t); w[t] = k; ins(p,t);
  if (l==r) return;
  int mid=(l+r)>>1;
  if (pos<=mid) modify(p*2+1,l,mid,pos,k);
    else modify(p*2+2,mid+1,r,pos,k);
}
 
int prev_number(int p,int k){
  int t=root[p], ret=-INF;
  while (true){
    if (t==0) break;
    if (w[t]<k){
      ret = w[t];
      t=son[t][1];
    } else
      t=son[t][0];
  }
  return ret;
}
 
int find_prev(int p,int l,int r,int L,int R,int k){
  if (l>R || L>r) return -INF;
  if (L<=l && R>=r)
    return prev_number(p,k);
  int mid=(l+r)>>1;
  int ret1 = find_prev(p*2+1,l,mid,L,R,k);
  int ret2 = find_prev(p*2+2,mid+1,r,L,R,k);
  return max(ret1,ret2);
}
 
int next_number(int p,int k){
  int t=root[p], ret=INF;
  while (true){
    if (t==0) break;
    if (w[t]>k){
      ret = w[t];
      t=son[t][0];
    } else
      t=son[t][1];
  }
  return ret;
}
 
int find_next(int p,int l,int r,int L,int R,int k){
  if (l>R || L>r) return INF;
  if (L<=l && R>=r)
    return next_number(p,k);
  int mid=(l+r)>>1;
  int ret1 = find_next(p*2+1,l,mid,L,R,k);
  int ret2 = find_next(p*2+2,mid+1,r,L,R,k);
  return min(ret1,ret2);
}
 
void work1(){
  scanf("%d%d%d",&l,&r,&k);
  ans = find_knumber_rank(0,1,n,l,r,k)+1;
  printf("%d\n",ans);
}
 
void work2(){
  scanf("%d%d%d",&l,&r,&k);
  int L = -INF, R = INF, Mid;
  while (L<=R){
    Mid = (L+R)/2;
    int t = find_knumber_rank(0,1,n,l,r,Mid);
    if (k>t) ans = Mid, L=Mid+1;
      else R=Mid-1;
  }
  printf("%d\n",ans);
}
 
void work3(){
  int pos;
  scanf("%d%d",&pos,&k);
  modify(0,1,n,pos,k);
  a[pos] = k;
}
 
void work4(){
  scanf("%d%d%d",&l,&r,&k);
  ans = find_prev(0,1,n,l,r,k);
  printf("%d\n",ans);
}
 
void work5(){
  scanf("%d%d%d",&l,&r,&k);
  ans = find_next(0,1,n,l,r,k);
  printf("%d\n",ans);
}
 
int main(){
  //freopen("3196.in","r",stdin);
  //freopen("3196.out","w",stdout);
  scanf("%d%d",&n,&m);
  for (i=1;i<=n;i++)
    scanf("%d",&a[i]);
  build_seg(0,1,n);
  while (m--){
    scanf("%d",&type);
    if (type==1) work1();
    if (type==2) work2();
    if (type==3) work3();
    if (type==4) work4();
    if (type==5) work5();
  }
  return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值