HNOI2017单旋

单旋
  • 这道题做法贼多,LCT,splay,线段树什么的貌似都行。
  • 像我这种渣渣只会线段树了(高级数据结构学了也不会用)。
  • 首先离线所有操作,因为不会有两个点值重复,所以直接离散。
  • 一颗线段树来维护所有点的深度,并将所有值丢进\(set\)中。
  • 插入操作,在set找到前驱后继,前驱没有右儿子就放前驱右儿子,否则放后继左儿子,同时用\(ch\)和\(fa\)假装模拟树的形态。
  • 旋转操作,在\(set\)里找到节点,可以发现旋转操作该点儿子深度不变,其他点深度加一,处理一下父子关系,然后线段树修改区间即可。
  • 删除操作,先旋转操作,\(root\)一定只有一个儿子,直接删掉\(root\)即可,将所有点深度减一
    // luogu-judger-enable-o2
    #include<bits/stdc++.h>
    using namespace std;
    typedef int sign;
    typedef long long ll;
    #define For(i,a,b) for(register sign i=(sign)a;i<=(sign)b;++i)
    #define Fordown(i,a,b) for(register sign i=(sign)a;i>=(sign)b;--i)
    const int N=1e5+5;
    bool cmax(sign &a,sign b){return (a<b)?a=b,1:0;}
    bool cmin(sign &a,sign b){return (a>b)?a=b,1:0;}
    template<typename T>inline T read()
    {
    T f=1,ans=0;
    char ch=getchar();
    while(!isdigit(ch)&&ch!=‘-‘)ch=getchar();
    if(ch==‘-‘)f=-1,ch=getchar();
    while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch-‘0‘),ch=getchar();
    return ans*f;
    }
    template<typename T>inline void write(T x,char y)
    {
    if(x==0)
    {
        putchar(‘0‘);putchar(y);
        return;
    }
    if(x<0)
    {
        putchar(‘-‘);
        x=-x;
    }
    static char wr[20];
    int top=0;
    for(;x;x/=10)wr[++top]=x%10+‘0‘;
    while(top)putchar(wr[top--]);
    putchar(y);
    }
    void file()
    {
    #ifndef ONLINE_JUDGE
        freopen("3721.in","r",stdin);
        freopen("3721.out","w",stdout);
    #endif
    }
    int n,opt[N][2];
    int a[N],top;
    void input()
    {
    n=read<int>();
    For(i,1,n)
    {
        opt[i][0]=read<int>();
        if(opt[i][0]==1)a[++top]=read<int>(),opt[i][1]=a[top];
    }
    }
    namespace Tree
    {
    #define mid ((l+r)>>1)
    #define lson h<<1,l,mid
    #define rson h<<1|1,mid+1,r
    ll lazy[N<<2],sum[N<<2];
    void push_down(int h,int l,int r)
    {
        if(!lazy[h])return;
        int ls=h<<1,rs=ls|1;
        lazy[ls]+=lazy[h];lazy[rs]+=lazy[h];
        sum[ls]+=lazy[h]*1ll*(mid-l+1);
        sum[rs]+=lazy[h]*1ll*(r-mid);
        lazy[h]=0;
    }
    void push_up(int h)
    {
        sum[h]=sum[h<<1]+sum[h<<1|1];
    }
    void update(int h,int l,int r,int s,int t,int v)
    {
        if(s<=l&&r<=t)
        {
            lazy[h]+=v;
            sum[h]+=1ll*v*1ll*(r-l+1);
        }
        else
        {
            push_down(h,l,r);
            if(s<=mid)update(lson,s,t,v);
            if(mid<t)update(rson,s,t,v);
            push_up(h);
        }
    }
    int query(int h,int l,int r,int pos)
    {
        if(l==r)return sum[h];
        push_down(h,l,r);
        int res;
        if(pos<=mid)res=query(lson,pos);
        else res=query(rson,pos);
        push_up(h);
        return res;
    }
    void modify(int h,int l,int r,int pos,int v)
    {
        if(l==r)sum[h]=v;
        else
        {
            push_down(h,l,r);
            if(pos<=mid)modify(lson,pos,v);
            else modify(rson,pos,v);
            push_up(h);
        }
    }
    }
    set<int>s;
    set<int>::iterator it;
    int root,ch[N][2],fa[N];
    typedef pair<int,int>pii;
    #define fir first
    #define sec second
    void insert(int x)
    {
    int pre,predep;
    it=s.insert(x).fir;
    if(!root)
    {
        root=x;
        Tree::modify(1,1,n,x,1);
        puts("1");
        return;
    }
    if(it==s.begin())
    {
        ++it;pre=*it;
        fa[x]=pre;ch[pre][0]=x;
    }
    else
    {
        --it;
        if(!ch[*it][1])
        {
            pre=*it;
            fa[x]=pre;
            ch[pre][1]=x;
        }
        else
        {
            ++it;++it;
            pre=*it;
            fa[x]=pre;
            ch[pre][0]=x;
        }
    }
    predep=Tree::query(1,1,n,pre);
    write(predep+1,‘\n‘);
    Tree::modify(1,1,n,x,predep+1);
    }
    void clear(int x)
    {
    ch[x][0]=ch[x][1]=fa[x]=0;
    }
    void rotate_min()
    {
    it=s.begin();
    int x=*it;
    if(x==root){puts("1");return;}
    int y=ch[x][1],oldroot=root,pre=fa[x];
    write(Tree::query(1,1,n,x),‘\n‘);
    if(y)Tree::update(1,1,n,x+1,fa[x]-1,-1);
    Tree::update(1,1,n,1,n,1);
    Tree::modify(1,1,n,x,1);
    root=x;
    ch[x][1]=oldroot;fa[oldroot]=x;
    ch[pre][0]=y;fa[y]=pre;
    }
    void del_min()
    {
    rotate_min();
    s.erase(root);
    Tree::update(1,1,n,1,n,-1);
    if(!ch[root][0]&&!ch[root][1])clear(root),root=0;
    else
    {
        int oldroot=root;
        root=ch[root][1];
        clear(oldroot);fa[root]=0;
    }
    }
    void rotate_max()
    {
    it=s.end();--it;
    int x=*it;
    if(x==root){puts("1");return;}
    write(Tree::query(1,1,n,x),‘\n‘);
    int y=ch[x][0],oldroot=root,pre=fa[x];
    if(y)Tree::update(1,1,n,fa[x]+1,x-1,-1);
    Tree::update(1,1,n,1,n,1);
    Tree::modify(1,1,n,x,1);
    root=x;
    fa[oldroot]=x;ch[x][0]=oldroot;
    ch[pre][1]=y;fa[y]=pre;
    }
    void del_max()
    {
    rotate_max();
    s.erase(root);
    Tree::update(1,1,n,1,n,-1);
    if(!ch[root][0]&&!ch[root][1])clear(root),root=0;
    else
    {
        int oldroot=root;
        root=ch[root][0];
        clear(oldroot);fa[root]=0;
    }
    }
    void work()
    {
    sort(a+1,a+top+1);
    For(i,1,n)
    {
        if(opt[i][0]==1)
        {
            opt[i][1]=lower_bound(a+1,a+top+1,opt[i][1])-a;
            insert(opt[i][1]);
        }
        else if(opt[i][0]==2)rotate_min();
        else if(opt[i][0]==3)rotate_max();
        else if(opt[i][0]==4)del_min();
        else if(opt[i][0]==5)del_max();
    }
    }
    int main()
    {
    file();
    input();
    work();
    return 0;
    }

原文地址:https://www.cnblogs.com/dengyixuan/p/8361944.html

时间: 2024-10-22 14:12:39

HNOI2017单旋的相关文章

bzoj4825 [Hnoi2017]单旋

4825: [Hnoi2017]单旋 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 520  Solved: 247[Submit][Status][Discuss] Description H 国是一个热爱写代码的国家,那里的人们很小去学校学习写各种各样的数据结构.伸展树(splay)是一种数据 结构,因为代码好写,功能多,效率高,掌握这种数据结构成为了 H 国的必修技能.有一天,邪恶的"卡"带着 他的邪恶的"常数"

【BZOJ4825】[Hnoi2017]单旋 线段树+set

[BZOJ4825][Hnoi2017]单旋 Description H 国是一个热爱写代码的国家,那里的人们很小去学校学习写各种各样的数据结构.伸展树(splay)是一种数据结构,因为代码好写,功能多,效率高,掌握这种数据结构成为了 H 国的必修技能.有一天,邪恶的“卡”带着他的邪恶的“常数”来企图毁灭 H 国.“卡”给 H 国的人洗脑说,splay 如果写成单旋的,将会更快.“卡”称“单旋 splay”为“spaly”.虽说他说的很没道理,但还是有 H 国的人相信了,小 H 就是其中之一,s

BZOJ4825:[HNOI2017]单旋

4825: [Hnoi2017]单旋 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 550  Solved: 258[Submit][Status][Discuss] Description H 国是一个热爱写代码的国家,那里的人们很小去学校学习写各种各样的数据结构.伸展树(splay)是一种数据 结构,因为代码好写,功能多,效率高,掌握这种数据结构成为了 H 国的必修技能.有一天,邪恶的“卡”带着 他的邪恶的“常数”来企图毁灭 H 国.“卡”给

[HNOI2017]单旋

标签:线段树+set 题解: 此题的标题为splay,所以我们可以排除这道题的正解是splay的可能性.然后我们发现只有最值的单旋,而且,三点一线不需要先旋转父亲.通过手玩我们可以发现,就是把最值直接移到最顶端作为根节点,然后其他的点以及他们之间的父子关系全部都没有变化.于是就只要求深度了. 我们发现,最小值,他没有左子树,而右子树在单旋之后深度不变(-1+1),而其他的点深度全部+1.如果再删掉根节点,全部的点深度-1.于是就可以使用线段树,维护每一个点的深度. 首先输入所有的操作,对于全部的

[AH2017/HNOI2017]单旋

题目描述 H国是一个热爱写代码的国家,那里的人们很小去学校学习写各种各样的数据结构.伸展树(splay)是一种数据结构,因为代码好写,功能多,效率高,掌握这种数据结构成为了H国的必修技能.有一天,邪恶的"卡"带着他的邪恶的"常数"来企图毁灭H国."卡"给H国的人洗脑说,splay如果写成单旋的,将会更快."卡"称"单旋splay"为"spaly".虽说他说的很没道理,但还是有H国的人相信

[2017.11.29]BZOJ4825[Hnoi2017]单旋

1 #include<bits/stdc++.h> 2 #define M 100010 3 #define RG register 4 #define inf 0x3f3f3f3f 5 using namespace std; 6 bool rev[M]; 7 set<int> tr; 8 set<int>::iterator it; 9 int m,rt,tp,big,cnt,cur,dau,dep,loc,sml,sum,tmp,c[M],fa[M],sz[M],

BZOJ 4825 [Hnoi2017]单旋

题解:LCT维护Splay形态 Splay后发现只会有几个点发生变化,用LCT维护一下就可以了 在Splay中维护siz 还可以用Splay维护DFS序,旋转后DFS序不变,深度以子树为单位变化 天真的我以为直接模拟Splay可以A掉QWQ #include<iostream> #include<cstdio> #include<cstring> #include<map> using namespace std; const int maxn=100009

AC日记——「HNOI2017」单旋 LiBreOJ 2018

#2018. 「HNOI2017」单旋 思路: set+线段树: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 100005 #define maxtree maxn<<2 int val[maxtree],tag[maxtree],L[maxtree],R[maxtree],mid[maxtree]; int op[maxn],ki[maxn],bi[maxn],cnt,size,n,ch[maxn]

[HNOI 2017]单旋

Description H 国是一个热爱写代码的国家,那里的人们很小去学校学习写各种各样的数据结构.伸展树(splay)是一种数据 结构,因为代码好写,功能多,效率高,掌握这种数据结构成为了 H 国的必修技能.有一天,邪恶的“卡”带着 他的邪恶的“常数”来企图毁灭 H 国.“卡”给 H 国的人洗脑说,splay 如果写成单旋的,将会更快.“卡”称 “单旋 splay”为“spaly”.虽说他说的很没道理,但还是有 H 国的人相信了,小 H 就是其中之一,spaly 马 上成为他的信仰. 而 H