zoukankan      html  css  js  c++  java
  • bzoj1861[Zjoi2006]Book 书架

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1861

    Splay模板。

    这种写法的建树很好,创建虚拟的1点和n+2点,实际点变成2~n+1,就能自如应对“top”和“bottom”操作了。

    一直不太理解Splay里点的角标、值和rank的关系。现在明白rank表示位置,只和siz有关。值和角标不会改变,可以记录一些别的信息。

      (注意别把角标和rank搞混)

    有一些注意地方:

      1.那个 if((c[y][0]==x)^(c[z][0]==y)),意为如果是拐一下的就先转中间点,如果是顺着的就先转最底下的点;

      2.注意update先弄底下的点;

      3.用scanf("%s",ch)输入字符串。

      4.为了建虚拟的1,输入从2开始。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int N=80005,INF=0x7fffffff;
    int n,m,a[N],pos[N],v[N],c[N][2],fa[N],siz[N],rt;
    char ch[10];
    void update(int x){siz[x]=siz[c[x][0]]+siz[c[x][1]]+1;}
    void build(int l,int r,int f)
    {
        if(l>r)return;
        if(l==r)
        {
            v[l]=a[l];siz[l]=1;fa[l]=f;
            c[f][l>f]=l;return;
        }
        int mid=((l+r)>>1);
        build(l,mid-1,mid);build(mid+1,r,mid);
        v[mid]=a[mid];fa[mid]=f;c[f][mid>f]=mid;
        update(mid);
    }
    void rotate(int x,int &k)
    {
        int y=fa[x],z=fa[y],d=(x==c[y][1]);
        if(y!=k)c[z][y==c[z][1]]=x;
        else k=x;
        fa[x]=z;fa[y]=x;fa[c[x][!d]]=y;
        c[y][d]=c[x][!d];c[x][!d]=y;
        update(y);update(x);    //
    }
    void splay(int x,int &k)
    {
        int y,z;
        while(x!=k)
        {
            y=fa[x];z=fa[y];
            if(y!=k)
            {
                if((c[y][0]==x)^(c[z][0]==y))
                    rotate(x,k);
                else rotate(y,k);
            }
            rotate(x,k);
        }
    }
    int find(int k,int rank)
    {
        int d=siz[c[k][0]]+1;
        if(rank==d)return k;
        if(rank<d)return find(c[k][0],rank);
        return find(c[k][1],rank-d);
    }
    void del(int k)
    {
        int x=find(rt,k-1),y=find(rt,k+1);
        splay(x,rt);splay(y,c[x][1]);
        fa[c[y][0]]=0;siz[c[y][0]]=0;c[y][0]=0;//这里的c[y][0]不是k,k是rank,以大小判断;c[y][0]是角标,表示原位置 
        update(y);update(x);
    }
    void move(int cr,int tmp)
    {
        int x,y,z=pos[cr],rank;
        splay(z,rt);rank=siz[c[z][0]]+1;
        del(rank);
        if(tmp==-INF)x=find(rt,1),y=find(rt,2);
        else if(tmp==INF)x=find(rt,n),y=find(rt,n+1);
        else x=find(rt,rank+tmp-1),y=find(rt,rank+tmp);
        splay(x,rt);splay(y,c[x][1]);
        fa[z]=y;c[y][0]=z;siz[z]=1;
        update(y);update(x);
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=2;i<=n+1;i++)scanf("%d",&a[i]),pos[a[i]]=i;//2~n+1为了虚拟的1 
        build(1,n+2,0);
        int cr,tp;rt=((n+3)>>1);
        for(int i=1;i<=m;i++)
        {
            scanf("%s",ch);scanf("%d",&cr);
            if(ch[0]=='T')move(cr,-INF);
            if(ch[0]=='B')move(cr,INF);
            if(ch[0]=='I')scanf("%d",&tp),move(cr,tp);
            if(ch[0]=='A')splay(pos[cr],rt),printf("%d
    ",siz[c[rt][0]]-1);
            if(ch[0]=='Q')printf("%d
    ",v[find(rt,cr+1)]);
        }
        return 0;
    }
  • 相关阅读:
    常用记录
    golang学习笔记之UDP:server端与client端
    golang学习笔记之tcp简单实现:server端与client端
    golang学习笔记之channel
    golang学习笔记之单元测试和压力测试
    Ubuntu 18.04桌面版安装
    Nas服务器使用xampp修改端口号
    Laravel使用Supervisor管理linux自动队列
    php 设计模式学习笔记之单例模式
    终极二分查找--传说十个人写九个有bug
  • 原文地址:https://www.cnblogs.com/Narh/p/9167244.html
Copyright © 2011-2022 走看看