zoukankan      html  css  js  c++  java
  • [ZJOI2006]书架

    题目描述

    有n本书从上到下放,有5种操作:

    1.将编号为s的书放在最上面

    2.把编号为s的书放在最下面

    3.把编号为s的书上下移动一个位置或者不动

    4.询问编号为s的书上面的书的个数

    5.从上面数第k个书的编号

    100%的数据,n,m <= 80000

    题解

    序列的平衡树。前后插入最值方便些。下标为编号

    1.在原序列上删除,再插入在第一个数之后。

    2.在原序列上删除,再插入在第n个数(因为自己出来了,最开始又有最值)之后。

    3.不动就不管。他在原序列的位置为pos,先删除。向上移动的话插入在第pos-2个数之后;向下移动插入在第pos个数之后(自己出来了)。

    4.把s旋到根,输出左儿子的size-1(最值)

    5.查询第k+1即可

    需要注意的就是-1是向上(可能只有我搞错,蠢哭);求编号s的位置,不是直接左儿子的size+1(因为不在根,再次蠢哭);

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn=80005;
    int n,m,root;
    int a[maxn];
    struct Splay{
      int fa,size,s[2];
    }tr[maxn];
    
    template<class T>inline void read(T &x){
      x=0;int f=0;char ch=getchar();
      while(!isdigit(ch)) {f|=(ch=='-');ch=getchar();}
      while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
      x= f ? -x : x ;
    }
    
    void update(int x){
      tr[x].size=tr[tr[x].s[0]].size+tr[tr[x].s[1]].size+1;
    }
    
    int build(int f,int l,int r){
      if(l>r) return 0;
      int mid=(l+r)>>1,now=a[mid];
      tr[now].fa=f;
      tr[now].s[0]=build(now,l,mid-1);
      tr[now].s[1]=build(now,mid+1,r);
      update(now);
      return now;
    }
    
    int find(int x){
      int now=root;
      while(1){
        if(tr[tr[now].s[0]].size>=x){now=tr[now].s[0];continue;}
        x-=tr[tr[now].s[0]].size;
        if(x==1) return now;
        x--;
        now=tr[now].s[1];
      }
    }
    
    int get(int x){return tr[tr[x].fa].s[1]==x;}
    
    void connect(int x,int y,int d){
      tr[x].fa=y;
      tr[y].s[d]=x;
    }
    
    void rotate(int x){
      int f=tr[x].fa,ff=tr[f].fa;
      int d1=get(x),d2=get(f);
      int cs=tr[x].s[d1^1];
      connect(x,ff,d2);
      connect(f,x,d1^1);
      connect(cs,f,d1);
      update(f);
      update(x);
    }
    
    void splay(int x,int go){
      if(go==root) root=x;
      go=tr[go].fa;
      while(tr[x].fa!=go){
        int f=tr[x].fa;
        if(tr[f].fa==go) rotate(x);
        else if(get(x)==get(f)) {rotate(f);rotate(x);}
        else {rotate(x);rotate(x);}
      }
    }
    
    void del(int now){
      splay(now,root);
      int pos=tr[tr[now].s[0]].size+1;
      int x=find(pos-1),y=find(pos+1);
      splay(x,root);
      splay(y,tr[x].s[1]);
      tr[now].fa=0;
      tr[y].s[0]=0;
      update(y);
      update(x);
    }
    
    void put(int now,int pos){
      del(now);
      int x=find(pos),y=find(pos+1);
      splay(x,root);
      splay(y,tr[x].s[1]);
      tr[now].fa=y;
      tr[y].s[0]=now;
      update(y);
      update(x);
    }
    
    void insert(int now,int t){
      splay(now,root);
      int pos=tr[tr[now].s[0]].size+1;
      del(now);
      if(t==-1) pos-=2;
      int x=find(pos),y=find(pos+1);
      splay(x,root);
      splay(y,tr[x].s[1]);
      tr[y].s[0]=now;
      tr[now].fa=y;
      update(y);
      update(x);
    }
    
    void debug(int x){
      if(tr[x].s[0]) debug(tr[x].s[0]);
      if(x!=n+1&&x!=n+2) printf("%d ",x);
      if(tr[x].s[1]) debug(tr[x].s[1]);
    }
    
    int main(){
      read(n);read(m);
      for(int i=1;i<=n;i++) read(a[i+1]);
      a[1]=n+1;
      a[n+2]=n+2;
      root=build(0,1,n+2);
      for(int i=1;i<=m;i++){
        char op[10];
        scanf("%s",op);
        if(op[0]=='T'){
          int x;read(x);
          put(x,1);
        }
        else if(op[0]=='B'){
          int x;read(x);
          put(x,n);
        }
        else if(op[0]=='I'){
          int x,t;
          read(x);read(t);
          if(!t) continue;
          insert(x,t);
        }
        else if(op[0]=='A'){
          int x;read(x);
          splay(x,root);
          printf("%d
    ",tr[tr[x].s[0]].size-1);
        }
        else {
          int x;read(x);
          printf("%d
    ",find(x+1));
        }
        //putchar(10);
        //debug(root);
        //putchar(10);
      }
    }
    View Code

    还有说树状数组或者权值线段树可以做的,数组要开3倍(只能%%%)。

  • 相关阅读:
    leetcode刷题笔记四十四 通配符匹配
    leetcode刷题笔记四十三 字符串相乘
    leetcode刷题笔记四十二 接雨水
    Scala 学习 -- 其他集合类学习
    Scala 学习 -- 列表
    leetcode刷题笔记四十一 缺失的第一个正数
    HTML5每日一练之OL列表的改良
    HTML5边玩边学(1)画布实现方法
    html5 +css3 第一章学习和笔记
    HTML5每日一练之figure新标签的应用
  • 原文地址:https://www.cnblogs.com/sto324/p/11380286.html
Copyright © 2011-2022 走看看