BZOJ4825: [Hnoi2017]单旋

题目

BZOJ4825: [Hnoi2017]单旋

题解

这题我写了一上午+调了一下午

日啊。。这是道模板题啊,而且我还不是自己想出来的。。GG。

hnoi的题告诉了我我有多菜。sdoi还让我有点自信,,看到hnoi一道不会但是大家都说d1好简单能AK呀。

手动再见。

我们来说说这道题吧。

单旋最大值最小值的话,可以拿手模拟几棵树然后会发现树的形态变化极其微小。拿单旋最小值来说,设这个点叫u,如果u有右儿子,那么这个右儿子会变成u父亲的左儿子。然后根会变成u的右儿子。(u就是根的情况需要另外特判。)

然后怎么做第一个操作呢。发现插入一个数的时候,要么和它前驱是父子关系要么和它后继是父子关系。(可以通过中序遍历有序来说明)。然后前驱后继在原来的树中也是父子关系。要么是前驱是后继的左儿子,要么后继是前驱的右儿子。所以就能确定,这两个位置,前驱的右儿子,后继的左儿子,哪个为空插哪里(有且仅有一个会为空)。然后就lct大力乱搞就好了。

关于怎么定位左右儿子以及原树的父亲。。我比较弱智。另外用了一个树来专门维护这个形态。。(反正变化极其微小嘛)。qwq大神们有没有什么好的方法。

(调试到昏厥)

//QWsin
#include<map>
#include<set>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

const int maxn=100000+10;

int root;//记录在spaly上的根节点的值 
//map<int,int>id;

//inline void output();

namespace lct{
    struct Node{
        int rev,sz;
        Node *ch[2],*fa;
        Node(){rev=0;sz=1;ch[0]=ch[1]=fa=NULL;}
        inline void up(){
            sz=1;
            if(ch[0]) sz+=ch[0]->sz;
            if(ch[1]) sz+=ch[1]->sz;    
        }
        inline void push()
        {
            if(rev){
                swap(ch[0],ch[1]);
                if(ch[0]) ch[0]->rev^=1;
                if(ch[1]) ch[1]->rev^=1;
                rev=0;
            }
        }
    };

    Node *node[maxn],*tmp[maxn];

    inline void init(int n){
        for(int i=1;i<=n;++i) node[i]=new Node();
    }

    inline int pd(Node* p){return p->fa->ch[1]==p;}
    inline int is_root(Node* p){
        return !(p->fa)|| (p->fa->ch[0]!=p&&p->fa->ch[1]!=p);   
    }

    inline void rotate(Node* p)
    {
        int c=pd(p)^1;Node* t=p->fa;    
        t->ch[c^1]=p->ch[c];
        if(p->ch[c]) p->ch[c]->fa=t;
        p->fa=t->fa;
        if(!is_root(t)) p->fa->ch[pd(t)]=p;
        t->fa=p;p->ch[c]=t;t->up();p->up();
    }

    inline void splay(Node* p)
    {
        int top=0;
        for(Node*t=p;;t=t->fa)
        {
            tmp[++top]=t;
//          if(top>maxn) {int t=1/0;}
            if(is_root(t)) break;   
        }
        for(;top>=1;--top) tmp[top]->push();
//      output();
        for(;!is_root(p);rotate(p))
            if(!is_root(p->fa)) rotate(pd(p)==pd(p->fa) ? p->fa:p);
    }

    inline void access(Node* p){
        for(Node* pre=NULL;p;pre=p,p=p->fa)
        {
            splay(p),p->ch[1]=pre,p->up();  
//          output();
        }
    }

    inline void make_root(Node* p){
        access(p);
//      output();
        splay(p);
//      output();
        p->rev=1;
    }
    inline void link(Node* a,Node *b){
        make_root(a);
        a->fa=b;    
    }
    inline void cut(Node* a,Node *b){
        make_root(a);
//      output();
        access(b);
//      output();
        splay(b);
//      output();
        b->ch[0]=a->fa=NULL;b->up();
    }
    inline int getdeep(Node* p){
        make_root(node[root]);
//      output();
        access(p);
//      output();
        splay(p);
//      output();
        int t=p->ch[0]?p->ch[0]->sz:0;
        return t+1;
    }

    inline void make_root(int x){make_root(node[x]);}
    inline void link(int a,int b){link(node[a],node[b]);}
    inline void cut (int a,int b){cut (node[a],node[b]);}
    inline int getdeep(int x){return getdeep(node[x]);}
}

//inline void output(){
//  
//  for(int i=1;i<=5;++i)
//  {
//      printf("node[%d]:\n",i);
//      printf("    sz=%d\n",lct::node[i]->sz); 
//      printf("    ch[0]=%d\n",id[(int)lct::node[i]->ch[0]]);
//      printf("    ch[1]=%d\n",id[(int)lct::node[i]->ch[1]]);
//      printf("    fa=%d\n",id[(int)lct::node[i]->fa]);
//      puts("");
//  }
//  puts("");
//}

int tmp[maxn],tmp_p;

struct OP{
    int k,a;
    OP(int a=0,int b=0):k(a),a(b){}
    inline void input(){
        scanf("%d",&k);
        if(k==1) {
            scanf("%d",&a);
            tmp[++tmp_p]=a;
        }
    }
}op[maxn];

int m;
inline void init_data()
{
    cin>>m;lct::init(m);
    for(int i=1;i<=m;++i) op[i].input();
    sort(tmp+1,tmp+tmp_p+1);
    int cc=unique(tmp+1,tmp+tmp_p+1)-tmp-1;
    for(int i=1;i<=m;++i) if(op[i].k==1){
        op[i].a=lower_bound(tmp+1,tmp+cc+1,op[i].a)-tmp;    
    }
}

set<int>st;
set<int>::iterator it;

struct Node{
    int val;
    Node *fa,*ch[2];
    Node(int val):val(val){fa=ch[0]=ch[1]=NULL;}
    inline void clear(){fa=ch[0]=ch[1]=NULL;}
}*node[maxn];

//操作1(val需要离散)
inline void insert(int val)
{
    it=st.insert(val).first;
    node[val]=new Node(val);

    if(st.size()!=1)
    {
        int done=0;
        if(it!=st.begin())
        {
            --it;
            if(node[*it]->ch[1]==NULL)
            {
                node[*it]->ch[1]=node[val];done=1;
                node[val]->fa=node[*it];
                lct::link(*it,val);
//              output();
                printf("%d\n",lct::getdeep(val));
            }
            ++it;
        }
        if(!done) {
            node[*(++it)]->ch[0]=node[val];
            node[val]->fa=node[*it];
            lct::link(*it,val);
            printf("%d\n",lct::getdeep(val));
        }
    }
    else root=val,puts("1");
}

#define rc node[*it]->ch[1]
#define lc node[*it]->ch[0]
#define Fa node[*it]->fa

inline void RotMin(int del)
{
    it=st.begin();
    printf("%d\n",lct::getdeep(*it));
//  output();

//  cout<<*it<<endl;

    if(*it==root)
    {
        if(!del) return ;
        if(rc){
            lct::cut(*it,rc->val);
            rc->fa=NULL;    
            root=rc->val;
        }
        st.erase(*it);return ;
    }

    lct::cut(*it,Fa->val);
//  output();
    Fa->ch[0]=rc;

    if(rc)
    {
        lct::cut(*it,rc->val);
        rc->fa=Fa;
        lct::link(rc->val,Fa->val);
    }

//  cout<<"*it="<<*it<<endl;

    if(!del)
    {
        node[*it]->clear();
        rc=node[root];
        node[root]->fa=node[*it];
        lct::link(*it,root);
//      output();
        root=*it;
    }
    else st.erase(*it);
}

inline void RotMax(int del)
{
    it=--(st.end());    
    printf("%d\n",lct::getdeep(*it));

    if(*it==root)
    {
        if(!del) return ;
        if(lc){
            lct::cut(*it,lc->val);
            lc->fa=NULL;    
            root=lc->val;
        }
        st.erase(*it);return ;
    }

//  cout<<"*it="<<*it<<endl;

    lct::cut(Fa->val,*it);
    Fa->ch[1]=lc;
    if(lc)
    {
        lc->fa=Fa;
        lct::cut(*it,lc->val);
        lct::link(Fa->val,lc->val);
    }
    if(!del)
    {
        node[*it]->clear();
        lc=node[root];
        node[root]->fa=node[*it];
        lct::link(root,*it);
        root=*it;
    }
    else st.erase(*it);
}

inline void solve()
{
//  id[0]=0;
//  for(int i=1;i<=m;++i) id[(int)lct::node[i]]=i;

    for(int i=1;i<=m;++i)
    {
//      printf("id= %d\n",i);

//      output();

//      if(op[i].k==2) {
//          int stop=1; 
//      }

        if(op[i].k==1) insert(op[i].a); 
        else if(op[i].k==2) RotMin(0);
        else if(op[i].k==3) RotMax(0);
        else if(op[i].k==4) RotMin(1);
        else if(op[i].k==5) RotMax(1);
    }
}

int main()
{
    init_data();
    solve();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值