zoukankan      html  css  js  c++  java
  • splay

    题目

    bzoj3224

    代码

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <cstdlib>
    #include <cstring>
    using namespace std;
    #define N 100005
    
    int n,root,cnt,ch[N][2];//splay本质为二叉排序树
    int fa[N],sz[N],w[N],num[N];//num记录出现次数 
    bool son(int x) {return ch[fa[x]][1]==x;}//判断是否为右儿子
    void link(int x,int y,int f)//将y赋为x的f儿子
    {
        //回看rotate,y要放入位置原先可能本来就没有节点,在此处特判
        if(x) ch[x][f]=y;
        if(y) fa[y]=x;
    }
    void pushup(int x){sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+num[x];}
    void rotate(int x,int &rt)//将x转至rt
    {
        int y=fa[x],z=fa[y],f=son(x);
        link(z,x,son(y));//x y相对z的大小关系是相同的,将x置于y的位置
        link(y,ch[x][f^1],f);//先看下一行,先将y要放的位置上原来的点接在y下方
        link(x,y,f^1);//若x>y(f=1),则y<x(f=0),^,反之同理
        //注意连接顺序,避免覆盖
        if(y==rt) rt=x;
        pushup(y);pushup(x);//y此时为x的子树,先更新
    }
    void splay(int x,int &rt)
    {
        while(x!=rt)//在x未转至rt时持续上移
        {
            int y=fa[x];
            if(y!=rt) rotate(son(x)^son(y)? x:y,rt);//??? 
            rotate(x,rt);
        }
    }
    void insert(int &rt,int x,int last)//当前节点,需插入的值,父亲
    {
        if(!rt)
        {
            rt=++cnt;//加入新节点,需要取址
            w[rt]=x;fa[rt]=last;sz[rt]=num[rt]=1;
            splay(rt,root);//cxy:没事多转转 
            return;
        }
        sz[rt]++;
        if(x==w[rt]) {num[rt]++;return;}
        insert(ch[rt][w[rt]<x? 1:0],x,rt);
    }
    int findv(int rt,int x)//返回权值为v的节点第几小 
    {
        if(w[rt]==x) return sz[ch[rt][0]]+1;
        if(w[rt]>x) return findv(ch[rt][0],x);
        return sz[ch[rt][0]]+num[rt]+findv(ch[rt][1],x);
    }
    int findk(int rt,int k)//返回第k大的节点下标
    {
        if(sz[ch[rt][0]]<k&&k<=sz[ch[rt][0]]+num[rt]) return rt;
        if(sz[ch[rt][0]]>=k) return findk(ch[rt][0],k);
        return findk(ch[rt][1],k-sz[ch[rt][0]]-num[rt]);
    }
    void del(int x)//删除权值为v的节点
    {
        int k=findv(root,x),t=findk(root,k);
        splay(t,root);//将节点转至根 
        if(num[t]>1) {sz[t]--;num[t]--;return;}//若有多个直接删除 
        //这两句换一下就会挂,是因为转的次数比较少吗??? 
        if(k==sz[root])//最大
        {
            root=ch[t][0];//直接换根
            ch[t][0]=fa[t]=0;//清空
            return; 
        }
        if(k==1)//最小
        {
            root=ch[t][1];
            ch[t][1]=fa[t]=0;
            return;
        }
        int l=findk(root,k-1),r=findk(root,k+1);//前驱后继
        splay(l,root);splay(r,ch[root][1]);//x必处于ch[r][0]
        ch[r][0]=0;
        pushup(r);pushup(l);
        return;
    }
    int lower(int rt,int x)//查询v的前驱
    {
        if(!rt) return -1;//查询到空节点,返回-1
        if(w[rt]>=x) return lower(ch[rt][0],x);
        int t=lower(ch[rt][1],x);
        return t==-1? rt:t;
    }
    int upper(int rt,int x)//查询v的后继
    {
        if(!rt) return -1;
        if(w[rt]<=x) return upper(ch[rt][1],x);
        int t=upper(ch[rt][0],x);
        return t==-1? rt:t;
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            int opt,x;scanf("%d%d",&opt,&x);
            if(opt==1) insert(root,x,0);
            if(opt==2) del(x);
            if(opt==3) printf("%d
    ",findv(root,x));
            if(opt==4) printf("%d
    ",w[findk(root,x)]);
            if(opt==5) printf("%d
    ",w[lower(root,x)]);
            if(opt==6) printf("%d
    ",w[upper(root,x)]);
        }
        return 0;
    }
  • 相关阅读:
    centos7下更新firefox
    Centos7宽带连接
    CAS和AQS
    java中锁的概念
    并发队列
    Callable和Future
    juc下的并发工具类和线程池
    死锁和线程安全的问题
    HashMap源码分析(java1.8)
    List集合框架面试题
  • 原文地址:https://www.cnblogs.com/XYZinc/p/8214318.html
Copyright © 2011-2022 走看看