BZOJ 3678 wangxz与OJ 缩点Splay

来源:互联网 发布:醉玲珑小说网络点击量 编辑:程序博客网 时间:2024/05/16 14:14

题目大意

维护一个序列,支持
1. 插入一段序列,这个序列以1递增
2. 删除连续的一段序列
3. 查询位置p的数是多少。

思路

简单Splay维护就可以。但是后来好像被卡了,还有rope什么乱搞的都被卡了。于是观察这个插入的序列,他是一个很有规律的数列,但是插入之后我们却不一定查找这个序列中的数字,我们可以将这个数列当成一个节点插入Splay中去,这样每个节点可以记录lr来表示这个点所代表的序列是什么。当要使用一个节点的时候,将这个节点从一个连续的序列中分裂出来在使用。

CODE

#define _CRT_SECURE_NO_WARNINGS#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define MAX 20010using namespace std;#define WORKPATH (root->son[1]->son[0])struct SplayTree{    int l, r, size;    SplayTree *son[2], *father;    bool Check() {        return father->son[1] == this;    }    void Combine(SplayTree *a, bool dir) {        son[dir] = a;        a->father = this;    }    void PushUp();}none, *nil = &none, *root;void SplayTree :: PushUp() {    size = son[0]->size + son[1]->size + r - l + 1;}int cnt,asks;int src[MAX];void Pretreatment(){    nil->son[0] = nil->son[1] = nil->father = nil;    nil->size = 0;}SplayTree *NewSplay(int l, int r){    SplayTree *re = new SplayTree();    re->l = l,re->r = r;    re->size = r - l + 1;    re->son[0] = re->son[1] = re->father = nil;    return re;}SplayTree *BuildTree(int l, int r){    if(l > r)   return nil;    int mid = (l + r) >> 1;     SplayTree *re = NewSplay(src[mid],src[mid]);    re->Combine(BuildTree(l, mid - 1), false);    re->Combine(BuildTree(mid + 1, r), true);    re->PushUp();    return re;}inline void Rotate(SplayTree *a, bool dir){    SplayTree *f = a->father;    f->son[!dir] = a->son[dir];    f->son[!dir]->father = f;    a->son[dir] = f;    a->father = f->father;    f->father->son[f->Check()] = a;    f->father = a;    f->PushUp();    if(root == f)   root = a;}inline void Splay(SplayTree *a, SplayTree *aim){    while(a->father != aim) {        if(a->father->father == aim)            Rotate(a,!a->Check());        else if(!a->father->Check()) {            if(!a->Check())                Rotate(a->father, true), Rotate(a, true);            else    Rotate(a, false), Rotate(a, true);        }        else {            if(a->Check())                Rotate(a->father, false), Rotate(a, false);            else    Rotate(a, true), Rotate(a, false);        }    }    a->PushUp();}SplayTree *Find(SplayTree *a, int k){    if(a->son[0]->size >= k)    return Find(a->son[0],k);    k -= a->son[0]->size;    if(k <= a->r - a->l + 1)    return a;    return Find(a->son[1], k - (a->r - a->l + 1));}SplayTree *FindMax(SplayTree *a){    if(a->son[1] == nil)    return a;    return FindMax(a->son[1]);}SplayTree *FindMin(SplayTree *a){    if(a->son[0] == nil)    return a;    return FindMin(a->son[0]);}inline void Spilt(int k){    if(!k || k == root->size)   return ;    ++k;    Splay(Find(root,k),nil);    SplayTree *pred = FindMax(root->son[0]);    SplayTree *succ = FindMin(root->son[1]);    Splay(pred,nil);    Splay(succ,root);    int left = root->son[0]->size + root->r - root->l + 1;    k -= left;    if(k != WORKPATH->r - WORKPATH->l + 1) {        int cnt = WORKPATH->r - WORKPATH->l + 1 - k;        WORKPATH->Combine(NewSplay(WORKPATH->r - cnt + 1,WORKPATH->r), true);        WORKPATH->r -= cnt;    }    if(k != 1) {        WORKPATH->Combine(NewSplay(WORKPATH->l, WORKPATH->l + k - 2), false);        WORKPATH->l += k - 1;    }}inline void SplaySeg(int x,int y){    Spilt(x - 1), Spilt(y + 1);    x++, y++;    Splay(Find(root, x - 1), nil);    Splay(Find(root, y + 1), root);}int main(){    Pretreatment();    cin >> cnt >> asks;    for(int i = 1; i <= cnt; ++i)        scanf("%d",&src[i]);    root = BuildTree(0, cnt + 1);    root->father = nil;    for(int flag, x, y, z, i = 1; i <= asks; ++i) {        scanf("%d", &flag);        if(!flag) {            scanf("%d%d%d", &x, &y, &z);            Spilt(x), Spilt(x + 1);            Splay(Find(root,x + 1), nil);            Splay(Find(root,x + 2), root);            root->son[1]->Combine(NewSplay(y, z), false);            root->son[1]->PushUp();            root->PushUp();        }        else if(flag == 1) {            scanf("%d%d",&x,&y);            SplaySeg(x,y);            root->son[1]->son[0] = nil;            root->son[1]->PushUp();            root->PushUp();        }        else if(flag == 2) {            scanf("%d",&x);            Spilt(x);            Splay(Find(root, x + 1), nil);            printf("%d\n",root->l);        }    }    return 0;}
1 0
原创粉丝点击