[BZOJ4923][Lydsy六月份月赛 .G][平衡树]K小值查询

直接上题解
这里写图片描述

学了发非旋转Treap,感觉常数有点大

#include <cstdio>
#include <iostream>
#include <algorithm>

using namespace std;

const int N=100010;

int n,m;
int a[N];

struct node{
  node *l,*r;
  int val,fix,size,minus;
  node(){ }
  node(int x):val(x),fix(rand()),size(1),l(NULL),r(NULL),minus(0){}
  void Push(){
    if(!minus) return ;
    if(l) l->val-=minus,l->minus+=minus;
    if(r) r->val-=minus,r->minus+=minus;
    minus=0;
  }
  void Up(){
    size=(l?l->size:0)+(r?r->size:0)+1;
  }
  int mark(int x){
    val-=x; minus+=x;
  }
}poor[N],*rt;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}

inline void rea(int &x){
  char c=nc(); x=0;
  for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}

inline int Size(node *x){
    return x?x->size:0;
}

typedef pair<node*,node*> Droot;

inline node *newnode(int x,int p){
  poor[p].val=x; poor[p].fix=rand(); poor[p].size=1; return poor+p;
}

inline node *Merge(node *x,node *y){
  if(!x||!y) return !x?y:x;
  x->Push(); y->Push();
  if(x->fix<y->fix){
    x->r=Merge(x->r,y);
    x->Up(); return x;
  }
  else{
    y->l=Merge(x,y->l);
    y->Up(); return y;
  }
}

inline node *Query(int k){
  node *x=rt;
  while(x){
    x->Push();
    if(k==Size(x->l)+1) return x;
    if(k>Size(x->l)) k-=Size(x->l)+1,x=x->r;
    else x=x->l;
    }
    return 0;
}

inline int Rank(int k){
    node *x=rt; int ret=0;
    while(x){
        x->Push();
        if(x->val<k) ret+=Size(x->l)+1,x=x->r;
        else x=x->l;
    }
    return ret+1;
}

Droot Split(node *x,int k){
    if(!x) return Droot(NULL,NULL);
    x->Push();
    if(k<=Size(x->l)){
        Droot ret=Split(x->l,k);
        x->l=ret.second; x->Up();
        ret.second=x; return ret;
    }
    else{
        Droot ret=Split(x->r,k-Size(x->l)-1);
        x->r=ret.first; x->Up();
        ret.first=x; return ret;
    }
}

bool Modify(int k){
    int cur=Rank(k+1);
    node *p=Query(cur);
    if(!p||p->val>2*k) return false;
    Droot x=Split(rt,cur-1);
    Droot y=Split(x.second,1);
    y.first->val-=k;
    rt=Merge(x.first,y.second);
    cur=Rank(y.first->val);
    x=Split(rt,cur-1);
    rt=Merge(x.first,Merge(y.first,x.second));
    return true;
}

int opt,k;

int main(){
  rea(n); rea(m);
  for(int i=1;i<=n;i++) rea(a[i]);
  sort(a+1,a+1+n);
  for(int i=1;i<=n;i++)
    poor[i]=node(a[i]),rt=Merge(rt,poor+i);
  while(m--){
    rea(opt); rea(k);
    if(opt==1) printf("%d\n",Query(k)->val);
    else{
      while(Modify(k));
      int cur;
      if((cur=Rank(k+1))<=n){
        Droot x=Split(rt,cur-1);
        x.second->mark(k);
        rt=Merge(x.first,x.second);
      }
    }
  }
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值