BZOJ 3678 wangxz与OJ 缩点Splay

题目大意

维护一个序列,支持

1. 插入一段序列,这个序列以1递增

2. 删除连续的一段序列

3. 查询位置p的数是多少。

思路

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

CODE

#define _CRT_SECURE_NO_WARNINGS

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 20010
using 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;
}
时间: 2024-10-12 02:23:49

BZOJ 3678 wangxz与OJ 缩点Splay的相关文章

BZOJ3678: wangxz与OJ

3678: wangxz与OJ Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 123  Solved: 23[Submit][Status] Description 某天,wangxz神犇来到了一个信息学在线评测系统(Online Judge).由于他是一位哲♂学的神犇,所以他不打算做题.他发现这些题 目呈线性排列,被标记为1~n号,每道题都有一个难度值(可以<=0).他决定与这些题目玩♂耍. 1.他可以在某个位置插♂入一些难度值特定的题目. 2

【BZOJ3678】wangxz与OJ Splay

[BZOJ3678]wangxz与OJ Description 某天,wangxz神犇来到了一个信息学在线评测系统(Online Judge).由于他是一位哲♂学的神犇,所以他不打算做题.他发现这些题 目呈线性排列,被标记为1~n号,每道题都有一个难度值(可以<=0).他决定与这些题目玩♂耍. 1.他可以在某个位置插♂入一些难度值特定的题目. 2.他可以吃♂掉(删除)一段题目. 3.他可以查询某个位置的题目的难度值. 维护一个初始有n个元素的序列(标记为1~n号元素),支持以下操作: 0 p a

[BZOJ 1179]ATM题解 Tarjan缩点+SPFA

[BZOJ 1179]ATM题解 Tarjan缩点+SPFA Description Input 第一行包含两个整数N.M.N表示路口的个数,M表示道路条数.接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号.接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数.接下来一行包含两个整数S.P,S表示市中心的编号,也就是出发的路口.P表示酒吧数目.接下来的一行中有P个整数,表示P个有酒吧的路口的编号 Output 输出一个整数,

bzoj3678: wangxz与OJ Splay缩点

RT. #include<bits/stdc++.h> #define L(t) (t)->c[0] #define R(t) (t)->c[1] #define F(t) (L(t)->s+1) #define G(t) (L(t)->s+(t)->u) #define M (l+r>>1) struct node{ int v,s,u; node* c[2]; node(int v,int s,int u,node* a,node* e) :v(v

bzoj 1588 [HNOI2002] 营业额统计 链表和Splay

来自HNOI 2002营业额的统计一题,这题以前是用链表水过的,最近看见许多splay的题,赶紧张一下知识. 题目大意就是对于一个序列,输出每个元素与它之前元素的差的最小值的和.先说链表的方法吧. 大概就是sort一下,记录每个点的rank.然后链表一下,很好理解,复杂度nlogn,瓶颈在于排序. #include<cstdio> #include<algorithm> #include<iostream> using namespace std; struct nod

BZOJ 3173: [Tjoi2013]最长上升子序列 [splay DP]

3173: [Tjoi2013]最长上升子序列 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1613  Solved: 839[Submit][Status][Discuss] Description 给定一个序列,初始为空.现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置.每插入一个数字,我们都想知道此时最长上升子序列长度是多少? Input 第一行一个整数N,表示我们要将1到N插入序列中,接下是N个数字,第k个数字Xk

BZOJ 1862: [Zjoi2006]GameZ游戏排名系统 Splay

Splay的基本操作,比较繁琐..... 有个一坑点,sorce会超int 1862: [Zjoi2006]GameZ游戏排名系统 Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 913  Solved: 343 [Submit][Status][Discuss] Description GameZ为他们最新推出的游戏开通了一个网站.世界各地的玩家都可以将自己的游戏得分上传到网站上.这样就可以看到自己在世界上的排名.得分越高,排名就越靠前.当两个玩家

BZOJ 题目1588: [HNOI2002]营业额统计(Splay Tree 求前驱后继)

1588: [HNOI2002]营业额统计 Time Limit: 5 Sec  Memory Limit: 162 MB Submit: 10828  Solved: 3771 [Submit][Status][Discuss] Description 营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额.分析营业情况是一项相当复杂的工作.由于节假日,大减价或者

BZOJ 3506 CQOI 2014 排序机械臂 Splay

题目大意:给出一个序列,给出一种排序方式,模拟这种排序方式排序,并输出每次找到的节点的位置. 思路:它让你做什么你就做什么,无非就是个Reverse,很简单.注意一下排序的时候权值相等的情况就行了. CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 100010 #define INF 0x3f3f3f3f using