NOIP 2017 列队

列队

题目传送门
我是向其他dalao学会了这个神奇的解法,但是在某知名优秀OJ上会被卡成90分
真是令人伤心&&头大
算了
我不打算卡常了
本蒟蒻只会用Splay这种低级数据结构
像树状数组常数这么小的神奇数据结构我根本不会
分块真是令人头大
算了,这题关分块p事
考虑每次的操作我们弹出(x,y),在调整矩阵,再将(x,y)加到矩阵右下角
大概是这样
复杂度很高的地方在于矩阵的调整,每个点暴力移动实在是太蛋疼了
我们考虑用Splay维护
对于每一行的前n-1个数建立Splay,对最后一列建立Splay,点在Splay上的移动的复杂度是令人愉悦的
这些Splay和平常的Splay不太一样
他们需要支持以下操作

  1. rotate&&splay(似乎是废话)
  2. 类似于vector的push_back
  3. 分裂节点(题目中节点数过多,内存问题需要通过大量节点的合并来解决)
  4. 弹出Splay中第k个数

听起来真TM简单
写起来真TM蛋疼

rotate

#define dir(x) (son[fa[x]][1]==x)
inline void rotate(long long root,long long d)
    {
        long long temp=son[root][d^1];
        son[root][d^1]=son[temp][d];
        if(son[root][d^1])fa[son[root][d^1]]=root;
        fa[temp]=fa[root];
        if(fa[root])son[fa[root]][dir(root)]=temp;
        fa[root]=temp,son[temp][d]=root;
        push_up(root),push_up(temp);
    }

这种路人皆知的操作为什么我还要粘

Splay

inline void splay(long long root,long long goal)
    {
        while(fa[root]^goal)
        {
            if(fa[fa[root]]^goal&&dir(root)==dir(fa[root]))
            rotate(fa[fa[root]],dir(root)^1);
            rotate(fa[root],dir(root)^1);
        }
        push_up(root);
        if(!goal)Root=root;
    }

我怎么把splay也给粘上来了

new_node(制造新节点)

inline long long new_node(long long left,long long right)
    {
        long long temp=++Splay_size;
        l[temp]=left,r[temp]=right;
        size[temp]=r[temp]-l[temp]+1;
        return temp;
    }

注意left,right表示这个节点所代表的区间(节点信息为了省内存而合并)

Split

神奇的分裂节点术来了

inline long long split(long long x,long long k)//将节点x的前k个信息保留在x中,剩余的作为新节点返回
    {
        k+=l[x];
        long long temp=new_node(k,r[x]);
        r[x]=k-1;
        if(!son[x][1])//维护中序遍历,让新节点在x的右侧一个的位置
        son[x][1]=temp,fa[temp]=x;
        else
        {
            long long root=son[x][1];
            while(son[root][0])root=son[root][0];
            son[root][0]=temp,fa[temp]=root;//找到x右侧第一个点的位置
            while(root^x)push_up(root),root=fa[root];
        }
        splay(temp,0);//每次拉到根维护信息
        return temp;
    }

Pop_kth

更神奇的弹出第k个节点来了

inline long long pop_kth(long long k)
    {
        long long root=Root;
        while(true)
        {
            if(k<=size[son[root][0]])root=son[root][0];
            else 
            {
                k-=size[son[root][0]];
                if(k<=r[root]-l[root]+1)
                {
                    if(k^(r[root]-l[root]+1))split(root,k);//如果不是最右面的信息,就要把右面的信息split掉
                    if(k^1)root=split(root,k-1);//如果不是最左边的信息,就要把左边的信息split掉
                    break;
                }
                else
                k-=r[root]-l[root]+1,root=son[root][1];
            }
        }
        splay(root,0);
        fa[son[root][0]]=fa[son[root][1]]=0;//删除根,一会将根弹出
        if(!son[root][0])Root=son[root][1];
        else
        {
            long long temp=son[root][0];
            while(son[temp][1])temp=son[temp][1];
            splay(temp,0);
            fa[son[root][1]]=temp,son[temp][1]=son[root][1],Root=temp;
            push_up(temp);
        }
        return l[root];
    }

Push_back

inline void push_back(long long x)
    {
        long long root=Root,temp=new_node(x,x);
        if(!Root)
        {
            Root=temp;
            return;
        }
        while(son[root][1])root=son[root][1];
        splay(root,0);
        son[root][1]=temp;
        fa[temp]=root;
        push_up(root);
    }

似乎没了
下面是整体代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#define MAXN 2000010
using namespace std;
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(long long &x)
{
    long long s=0,w=1;
    char c=nc();
    while(!isdigit(c)){if(c=='-')w=-1;c=nc();}
    while(isdigit(c)){s=(s<<3)+(s<<1)+c-'0';c=nc();}
    x=s*w;
}
inline void write(long long x)
{
    if(x<0)x=-x,putchar('-');
    if(x>9)write(x/10);
    putchar('0'+x%10);
}
long long size[MAXN],l[MAXN],r[MAXN],fa[MAXN],son[MAXN][2],Splay_size;
struct Splay_Tree
{
    long long Root;
    #define push_up(root) (size[root]=size[son[root][0]]+size[son[root][1]]+r[root]-l[root]+1)
    #define dir(x) (son[fa[x]][1]==x)
    inline void rotate(long long root,long long d)
    {
        long long temp=son[root][d^1];
        son[root][d^1]=son[temp][d];
        if(son[root][d^1])fa[son[root][d^1]]=root;
        fa[temp]=fa[root];
        if(fa[root])son[fa[root]][dir(root)]=temp;
        fa[root]=temp,son[temp][d]=root;
        push_up(root),push_up(temp);
    }
    inline void splay(long long root,long long goal)
    {
        while(fa[root]^goal)
        {
            if(fa[fa[root]]^goal&&dir(root)==dir(fa[root]))
            rotate(fa[fa[root]],dir(root)^1);
            rotate(fa[root],dir(root)^1);
        }
        push_up(root);
        if(!goal)Root=root;
    }
    inline long long new_node(long long left,long long right)
    {
        long long temp=++Splay_size;
        l[temp]=left,r[temp]=right;
        size[temp]=r[temp]-l[temp]+1;
        return temp;
    }
    inline long long split(long long x,long long k)
    {
        k+=l[x];
        long long temp=new_node(k,r[x]);
        r[x]=k-1;
        if(!son[x][1])
        son[x][1]=temp,fa[temp]=x;
        else
        {
            long long root=son[x][1];
            while(son[root][0])root=son[root][0];
            son[root][0]=temp,fa[temp]=root;
            while(root^x)push_up(root),root=fa[root];
        }
        splay(temp,0);
        return temp;
    }
    inline long long pop_kth(long long k)
    {
        long long root=Root;
        while(true)
        {
            if(k<=size[son[root][0]])root=son[root][0];
            else 
            {
                k-=size[son[root][0]];
                if(k<=r[root]-l[root]+1)
                {
                    if(k^(r[root]-l[root]+1))split(root,k);
                    if(k^1)root=split(root,k-1);
                    break;
                }
                else
                k-=r[root]-l[root]+1,root=son[root][1];
            }
        }
        splay(root,0);
        fa[son[root][0]]=fa[son[root][1]]=0;
        if(!son[root][0])Root=son[root][1];
        else
        {
            long long temp=son[root][0];
            while(son[temp][1])temp=son[temp][1];
            splay(temp,0);
            fa[son[root][1]]=temp,son[temp][1]=son[root][1],Root=temp;
            push_up(temp);
        }
        return l[root];
    }
    inline void push_back(long long x)
    {
        long long root=Root,temp=new_node(x,x);
        if(!Root)
        {
            Root=temp;
            return;
        }
        while(son[root][1])root=son[root][1];
        splay(root,0);
        son[root][1]=temp;
        fa[temp]=root;
        push_up(root);
    }
    inline void build(long long left,long long right)
    {
        Root=new_node(left,right);
    }
    #undef push_up
    #undef dir
}Splay[MAXN];
long long n,m,q,x,y,p;
int main()
{
    read(n),read(m),read(q);
    for(register long long i=1;i<=n;i++)
        Splay[i].build((i-1)*m+1,i*m-1);
    Splay[0].build(m,m);
    for(register long long i=2;i<=n;i++)
        Splay[0].push_back(i*m);
    while(q--)
    {
        read(x),read(y);
        Splay[x].push_back(Splay[0].pop_kth(x));
        p=Splay[x].pop_kth(y);
        write(p),putchar(10);
        Splay[0].push_back(p);
    }
}

猜你喜欢

转载自blog.csdn.net/assass_cannotin/article/details/79381270
今日推荐