题意:见下图
传说级别的NOI数据结构神题,像我这种弱渣花了一下午的时间才A掉,最后发现竟然是边界值的问题没处理好。。
这个题对Splay的所有操作基本是全了。
插入:新建一颗Splay Tree,然后把对应节点Splay到根的右儿子上,再把新建的树连上。
删除:把要删除的区间Splay到根的右儿子的左儿子上,递归free掉。(这里可以用数组优化,可以避免递归free节省时间)
修改,翻转:打标记,在需要的时候下传标记,和线段树差不多,翻转标记下传时,要将左右儿子的左右儿子分别交换。
求和:维护一个sum域。
求最大子列和:与线段树类似。维护一个区间从左边开始连续最大值,从右边开始连续最大值,整体的连续最大值。更新的时候注意下细节。不会的可以先去写vijos的小白逛公园,线段树的最大子列和,要比这个简单一些。详情见代码。
CODE(BZOJ5988ms):
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 600010
#define INF 0x7f7f7f7f
using namespace std;
const char INSERT[] = "INSERT";
const char DELETE[] = "DELETE";
const char REVERSE[] = "REVERSE";
const char GET_SUM[] = "GET-SUM";
const char MAX_SUM[] = "MAX-SUM";
const char MAKE_SAME[] = "MAKE-SAME";
struct Complex{
int val,size;
bool change,reverse;
int change_into;
int sum;
int l,r,all;
Complex *son[2],*father;
bool Check() {
return father->son[1] == this;
}
void Combine(Complex *a,bool dir) {
son[dir] = a;
a->father = this;
}
void Reverse() {
reverse ^= 1;
swap(son[0],son[1]);
swap(l,r);
}
void Change(int x) {
val = x;
sum = x * size;
l = r = all = max(sum,val);
change = true;
change_into = x;
}
}none,*nil = &none,*root = nil;
void Pretreatment();
inline Complex *NewComplex(int x);
inline void Rotate(Complex *a,bool dir);
inline void Splay(Complex *a,Complex *aim);
Complex *BuildTree(int l,int r);
inline void SplaySeg(int st,int ed);
inline void PushUp(Complex *a);
inline void PushDown(Complex *a);
void Delete(Complex *a);
Complex *FindK(Complex *a,int k);
void Print(Complex *a)
{
if(a == nil) return ;
PushDown(a);
PushUp(a);
Print(a->son[0]);
printf("%d ",a->val);
Print(a->son[1]);
}
int cnt,asks;
int pos,num;
int temp[MAX];
char s[20];
int main()
{
cin >> cnt >> asks;
Pretreatment();
for(int i = 1;i <= cnt; ++i)
scanf("%d",&temp[i]);
root = BuildTree(0,cnt + 1);
root->father = nil;
for(int i = 1;i <= asks; ++i) {
scanf("%s",s);
if(!strcmp(s,INSERT)) {
scanf("%d%d",&pos,&cnt),pos++;
for(int i = 1;i <= cnt; ++i)
scanf("%d",&temp[i]);
Splay(FindK(root,pos),nil);
Splay(FindK(root,pos + 1),root);
root->son[1]->Combine(BuildTree(1,cnt),false);
PushUp(root->son[1]),PushUp(root);
}
else if(!strcmp(s,DELETE)) {
scanf("%d%d",&pos,&cnt);
SplaySeg(pos,pos + cnt - 1);
Delete(root->son[1]->son[0]);
root->son[1]->son[0] = nil;
PushUp(root->son[1]),PushUp(root);
}
else if(!strcmp(s,MAKE_SAME)) {
scanf("%d%d%d",&pos,&cnt,&num);
SplaySeg(pos,pos + cnt - 1);
root->son[1]->son[0]->Change(num);
PushUp(root->son[1]),PushUp(root);
}
else if(!strcmp(s,REVERSE)) {
scanf("%d%d",&pos,&cnt);
SplaySeg(pos,pos + cnt - 1);
root->son[1]->son[0]->Reverse();
PushUp(root->son[1]),PushUp(root);
}
else if(!strcmp(s,GET_SUM)) {
scanf("%d%d",&pos,&cnt);
SplaySeg(pos,pos + cnt - 1);
printf("%d\n",root->son[1]->son[0]->sum);
}
else if(!strcmp(s,MAX_SUM)) {
int temp = root->size;
Splay(FindK(root,1),nil);
Splay(FindK(root,temp),root);
printf("%d\n",root->son[1]->son[0]->all);
}
}
return 0;
}
void Pretreatment()
{
nil->son[0] = nil->son[1] = nil;
nil->father = nil;
nil->size = 0;
nil->all = -INF;
temp[0] = temp[cnt + 1] = -INF;
}
inline Complex *NewComplex(int x)
{
Complex *re = new Complex();
re->son[0] = re->son[1] = nil;
re->size = 1;
re->sum = re->l = re->r = re->all = re->val = x;
re->change = re->reverse = false;
return re;
}
inline void Rotate(Complex *a,bool dir)
{
Complex *f = a->father;
PushDown(f),PushDown(a);
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;
PushUp(f);
if(root == f) root = a;
}
inline void Splay(Complex *a,Complex *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);
}
}
PushUp(a);
}
}
Complex *BuildTree(int l,int r)
{
if(l > r) return nil;
int mid = (l + r) >> 1;
Complex *now = NewComplex(temp[mid]);
now->Combine(BuildTree(l,mid - 1),false);
now->Combine(BuildTree(mid + 1,r),true);
if(l != r)
PushUp(now);
return now;
}
void Delete(Complex *a)
{
if(a == nil) return ;
Delete(a->son[0]),Delete(a->son[1]);
free(a);
}
inline void SplaySeg(int st,int ed)
{
st += 1,ed += 1;
Splay(FindK(root,st - 1),nil);
Splay(FindK(root,ed + 1),root);
}
Complex *FindK(Complex *a,int k)
{
PushDown(a);
if(k <= a->son[0]->size)
return FindK(a->son[0],k);
k -= a->son[0]->size;
if(k == 1) return a;
--k;
return FindK(a->son[1],k);
}
inline void PushDown(Complex *a)
{
if(a == nil) return ;
if(a->change) {
if(a->son[0] != nil)
a->son[0]->Change(a->change_into);
if(a->son[1] != nil)
a->son[1]->Change(a->change_into);
a->change = false;
}
if(a->reverse) {
if(a->son[0] != nil)
a->son[0]->Reverse();
if(a->son[1] != nil)
a->son[1]->Reverse();
a->reverse = false;
}
}
inline void PushUp(Complex *a)
{
if(a == nil) return ;
a->size = a->son[0]->size + a->son[1]->size + 1;
a->sum = a->son[0]->sum + a->son[1]->sum + a->val;
a->l = max(a->son[0]->l,a->son[0]->sum + a->val + max(0,a->son[1]->l));
a->r = max(a->son[1]->r,a->son[1]->sum + a->val + max(0,a->son[0]->r));
a->all = max(max(a->son[0]->all,a->son[1]->all),a->val+max(0,a->son[0]->r)+max(0,a->son[1]->l));
}
奉上读入优化版本,因为有的OJ卡这个题的常数(比如我们学校自己的oj)
同学帮着写的,效率十分可观,BZOJ3472ms就过了
CODE(读入优化):
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cctype>
#define MAX 600010
#define INF 0x7f7f7f7f
using namespace std;
inline int getc() {
static const int L = 1 << 15;
static char buf[L], *S = buf, *T = buf;
if (S == T) {
T = (S = buf) + fread(buf, 1, L, stdin);
if (S == T)
return EOF;
}
return *S++;
}
inline int getint() {
int c;
while(!isdigit(c = getc()) && c != '-');
bool sign = c == '-';
int tmp = sign ? 0 : c - '0';
while(isdigit(c = getc()))
tmp = (tmp << 1) + (tmp << 3) + c - '0';
return sign ? -tmp : tmp;
}
struct Twochar {
char c0, c1;
Twochar(char _c0 = 0, char _c1 = 0):c0(_c0),c1(_c1){}
};
inline Twochar getch() {
int c;
while((c = getc()) != 'I' && c != 'D' && c != 'M' && c != 'R' && c != 'G');
int c2 = getc();
c2 = getc();
if(c == 'I'&&c2=='S')getc(),getc(),getc();
if(c == 'D'&&c2=='L')getc(),getc(),getc();
if(c=='M'&&c2=='K')getc(),getc(),getc(),getc(),getc();
if(c=='R'&&c2=='V')getc(),getc(),getc(),getc();
if(c=='G'&&c2=='T')getc(),getc(),getc(),getc();
if(c=='M'&&c2=='X')getc(),getc(),getc(),getc();
return Twochar(c, c2);
}
struct Complex{
int val,size;
bool change,reverse;
int change_into;
int sum;
int l,r,all;
Complex *son[2],*father;
bool Check() {
return father->son[1] == this;
}
void Combine(Complex *a,bool dir) {
son[dir] = a;
a->father = this;
}
void Reverse() {
reverse ^= 1;
swap(son[0],son[1]);
swap(l,r);
}
void Change(int x) {
val = x;
sum = x * size;
l = r = all = max(sum,val);
change = true;
change_into = x;
}
}none,*nil = &none,*root = nil;
void Pretreatment();
inline Complex *NewComplex(int x);
inline void Rotate(Complex *a,bool dir);
inline void Splay(Complex *a,Complex *aim);
Complex *BuildTree(int l,int r);
inline void SplaySeg(int st,int ed);
inline void PushUp(Complex *a);
inline void PushDown(Complex *a);
void Delete(Complex *a);
Complex *FindK(Complex *a,int k);
int cnt,asks;
int pos,num;
int temp[MAX];
int main()
{
cnt = getint();
asks = getint();
Pretreatment();
for(int i = 1;i <= cnt; ++i)
temp[i] = getint();
root = BuildTree(0,cnt + 1);
root->father = nil;
Twochar s;
for(int i = 1;i <= asks; ++i) {
s = getch();
if(s.c0 == 'I' && s.c1 == 'S') {
pos=getint(),cnt=getint(),pos++;
for(int i = 1;i <= cnt; ++i)
temp[i]=getint();
Splay(FindK(root,pos),nil);
Splay(FindK(root,pos + 1),root);
root->son[1]->Combine(BuildTree(1,cnt),false);
PushUp(root->son[1]),PushUp(root);
}
else if(s.c0 == 'D' && s.c1 == 'L') {
pos=getint(),cnt=getint();
SplaySeg(pos,pos + cnt - 1);
Delete(root->son[1]->son[0]);
root->son[1]->son[0] = nil;
PushUp(root->son[1]),PushUp(root);
}
else if(s.c0 == 'M' && s.c1 == 'K') {
pos=getint(),cnt=getint(),num=getint();
SplaySeg(pos,pos + cnt - 1);
root->son[1]->son[0]->Change(num);
PushUp(root->son[1]),PushUp(root);
}
else if(s.c0 == 'R' && s.c1 == 'V') {
pos=getint(),cnt=getint();
SplaySeg(pos,pos + cnt - 1);
root->son[1]->son[0]->Reverse();
PushUp(root->son[1]),PushUp(root);
}
else if(s.c0 == 'G' && s.c1 == 'T') {
pos=getint(),cnt=getint();
SplaySeg(pos,pos + cnt - 1);
printf("%d\n",root->son[1]->son[0]->sum);
}
else if(s.c0 == 'M' && s.c1 == 'X') {
int temp = root->size;
Splay(FindK(root,1),nil);
Splay(FindK(root,temp),root);
printf("%d\n",root->son[1]->son[0]->all);
}
}
return 0;
}
void Pretreatment()
{
nil->son[0] = nil->son[1] = nil;
nil->father = nil;
nil->size = 0;
nil->all = -INF;
temp[0] = temp[cnt + 1] = -INF;
}
inline Complex *NewComplex(int x)
{
Complex *re = new Complex();
re->son[0] = re->son[1] = nil;
re->size = 1;
re->sum = re->l = re->r = re->all = re->val = x;
re->change = re->reverse = false;
return re;
}
inline void Rotate(Complex *a,bool dir)
{
Complex *f = a->father;
PushDown(f),PushDown(a);
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;
PushUp(f);
if(root == f) root = a;
}
inline void Splay(Complex *a,Complex *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);
}
}
}
PushUp(a);
}
Complex *BuildTree(int l,int r)
{
if(l > r) return nil;
int mid = (l + r) >> 1;
Complex *now = NewComplex(temp[mid]);
now->Combine(BuildTree(l,mid - 1),false);
now->Combine(BuildTree(mid + 1,r),true);
if(l != r)
PushUp(now);
return now;
}
void Delete(Complex *a)
{
if(a == nil) return ;
Delete(a->son[0]),Delete(a->son[1]);
free(a);
}
inline void SplaySeg(int st,int ed)
{
st += 1,ed += 1;
Splay(FindK(root,st - 1),nil);
Splay(FindK(root,ed + 1),root);
}
Complex *FindK(Complex *a,int k)
{
PushDown(a);
if(k <= a->son[0]->size)
return FindK(a->son[0],k);
k -= a->son[0]->size;
if(k == 1) return a;
--k;
return FindK(a->son[1],k);
}
inline void PushDown(Complex *a)
{
if(a == nil) return ;
if(a->change) {
if(a->son[0] != nil)
a->son[0]->Change(a->change_into);
if(a->son[1] != nil)
a->son[1]->Change(a->change_into);
a->change = false;
}
if(a->reverse) {
if(a->son[0] != nil)
a->son[0]->Reverse();
if(a->son[1] != nil)
a->son[1]->Reverse();
a->reverse = false;
}
}
inline void PushUp(Complex *a)
{
if(a == nil) return ;
a->size = a->son[0]->size + a->son[1]->size + 1;
a->sum = a->son[0]->sum + a->son[1]->sum + a->val;
a->l = max(a->son[0]->l,a->son[0]->sum + a->val + max(0,a->son[1]->l));
a->r = max(a->son[1]->r,a->son[1]->sum + a->val + max(0,a->son[0]->r));
a->all = max(max(a->son[0]->all,a->son[1]->all),a->val+max(0,a->son[0]->r)+max(0,a->son[1]->l));
}