题目大意
维护一个序列,支持
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