[题解] Luogu P2596 [ZJOI2006]书架

ajcxsu
ajcxsu 2018年01月18日
  • 75 次阅读

Problem

第一行有两个数n,m,分别表示书的个数以及命令的条数;第二行为n个正整数:第i个数表示初始时从上至下第i个位置放置的书的编号;第三行到m+2行,每行一条命令。命令有5种形式:
1. Top S——表示把编号为S的书房在最上面。
2. Bottom S——表示把编号为S的书房在最下面。
3. Insert S T——T∈{-1,0,1},若编号为S的书上面有X本书,则这条命令表示把这本书放回去后它的上面有X+T本书;
4. Ask S——询问编号为S的书的上面目前有多少本书。
5. Query S——询问从上面数起的第S本书的编号。

Konachan.com - 257570 2girls bow original pantyhose purple_eyes scarf seifuku skirt tagme_(artist) thighhighs tie white white_hair.png

Solution

一道Splay的入门题,据说。
我还专门为了这个去打了父指针维护版。
这种询问序列具体内容的大概都得打父指针维护版。

啊,关于置顶我用了个比较蠢的方法。首先把东西旋上来,然后合并左右子树。
然后左右子树最小旋上来,点插到右子树。
实际上只用把东西旋上来,然后左子树与其后继合并即可。也就是直接右子树最小旋上来,接左子树。
啊我真tm蠢。

以及这个题又再次告诉我们了指针清零的重要性。

Code

#include<bits/stdc++.h>
#define DEBUG dfs(root), cout<<endl
using namespace std;

struct Node *nil;
struct Node {
    int v,s,c;
    Node *ch[2],*f;
    Node (int v=0):v(v),s(1),c(1) { ch[0]=ch[1]=f=nil; }
    int dir() {
        if(f==nil) return -1;
        return f->ch[1]==this;
    }
    void upd() { s=c+ch[0]->s+ch[1]->s; }
} *root, *pos[80010];
#define INF (0x7fffffff)
void init() {
    nil=new Node(-INF);
    root=nil->ch[0]=nil->ch[1]=nil->f=nil;
    nil->s=nil->c=0;
}
void dfs(Node *x) {
    if(x==nil) return;
    dfs(x->ch[0]), cout<<x->v<<' ', dfs(x->ch[1]);
}

void rot(Node *x) {
    Node *y=x->f;
    int d=x->dir();
    y->ch[d]=x->ch[!d];
    if(x->ch[!d]!=nil) x->ch[!d]->f=y;

    x->f=y->f;
    if(y->f!=nil) y->f->ch[y->dir()]=x;

    x->ch[!d]=y, y->f=x;
    if(y==root) root=x;
    y->upd();
}

void splay(Node *f, Node *x) {
    while(x->f!=f) {
        Node *y=x->f, *z=y->f;
        if(z==f) rot(x);
        else if(x->dir()==y->dir()) rot(y), rot(x);
        else rot(x), rot(x);
    }
    x->upd();
}

Node* kth(Node *x, int k) {
    int ss=x->ch[0]->s;
    if(k<=ss) return kth(x->ch[0], k);
    else if(k<=ss+x->c) return x;
    else return kth(x->ch[1], k-ss-x->c);
}

void swp(Node *x, Node *y) {
    Node *&a=pos[x->v], *&b=pos[y->v];
    swap(x->v, y->v);
    swap(a,b);
}

void merge(Node *&x1, Node *&x2) {
    if(x1==nil) swap(x1,x2);
    splay(x1->f, kth(x1,x1->s));
    x1->ch[1]=x2, x2->f=x1, x1->upd();
    if(x2==nil) x2->f=nil;
    x2=nil;
}

void top(int x) {
    splay(nil, pos[x]);
    Node *nd=root;
    root=root->ch[0], root->f=nd->ch[1]->f=nil;
    merge(root, nd->ch[1]);
    nd->ch[0]=nd->ch[1]=nil;
    splay(nil, kth(root,1));
    root->ch[0]=nd, nd->f=root, nd->upd(), root->upd();
}

int n,m;
void bot(int x) {
    splay(nil, pos[x]);
    Node *nd=root;
    root=root->ch[0], root->f=nd->ch[1]->f=nil;
    merge(root, nd->ch[1]);
    nd->ch[0]=nd->ch[1]=nil;
    splay(nil, kth(root,n-1));
    root->ch[1]=nd, nd->f=root, nd->upd(), root->upd();
}

void ins(int x, int t) {
    if(!t) return;
    splay(nil, pos[x]);
    if(t==-1) {
        splay(root, kth(root->ch[0],root->ch[0]->s));
        if(root->ch[0]!=nil) swp(root->ch[0], root);
    }
    else {
        splay(root, kth(root->ch[1],1));
        if(root->ch[1]!=nil) swp(root->ch[1], root);
    }
}

int rank(int x) {
    splay(nil, pos[x]);
    return root->ch[0]->s;
}

int main() {
    ios::sync_with_stdio(false);
    init();
    cin>>n>>m;
    int na;
    cin>>na;
    pos[na]=root=new Node(na);
    Node *nd=root;
    for(int i=2;i<=n;i++) cin>>na, nd->ch[1]=new Node(na), nd->ch[1]->f=nd, nd=nd->ch[1], pos[na]=nd;
    splay(root, nd);
    string opt;
    int nb;
    while(m--) {
        cin>>opt>>na;
        if(opt[0]=='T') top(na);
        else if(opt[0]=='B') bot(na);
        else if(opt[0]=='I') cin>>nb, ins(na,nb);
        else if(opt[0]=='A') cout<<rank(na)<<endl;
        else cout<<kth(root, na)->v<<endl;
    }
    return 0;
}

本文链接:https://acxblog.site/archives/sol_luogu_2596.html
本文采用 CC BY-NC-SA 3.0 协议进行许可