您的位置:首页 > 其它

bzoj 1500 [NOI 2005] 维修数列

2015-04-22 00:10 471 查看
题目大意不多说了

貌似每个苦逼的acmer都要做一下这个splay树的模版题目吧

还是有很多操作的,估计够以后当模版了。。。。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;
const int N = 1000010;
const int INF = 0x3f3f3f3f;
#define ls ch[x][0]
#define rs ch[x][1]

struct SplayTree{
int ch
[2] , pre
;
int ml
, mr
, mm
; //区间最大
int val
, sz
, sum
, size , rt;
int rev
, to
; // lazy标记
int del
, top; //内部保存删除的数的位置,然后可以从其中提取位置给新进入的元素
int a
;

void push_up(int x)
{
sz[x] = sz[ls]+sz[rs]+1;
sum[x] = sum[ls]+sum[rs]+val[x];
/*********************/
ml[x] = max(ml[ls] , sum[ls]+val[x]+max(ml[rs] , 0));
mr[x] = max(mr[rs] , sum[rs]+val[x]+max(mr[ls] , 0));
mm[x] = max(mm[ls] , max(mm[rs] , max(ml[rs],0)+max(mr[ls],0)+val[x]));
/*********************/
}

void push_down(int x)
{
if(rev[x]){
if(ls){
rev[ls]^=1 ;
swap(ml[ls] , mr[ls]);
}
if(rs){
rev[rs]^=1 ;
swap(ml[rs] , mr[rs]);
}
swap(ls , rs);
rev[x] = 0;
}
/**to[x]的初始化要注意**/
if(to[x]!=-INF){
if(ls){
sum[ls] = sz[ls]*to[x];
ml[ls] = mr[ls] = mm[ls] = max(sum[ls] , to[x]);
val[ls] = to[ls] = to[x];
}
if(rs){
sum[rs] = sz[rs]*to[x];
ml[rs] = mr[rs] = mm[rs] = max(sum[rs] , to[x]);
val[rs] = to[rs] = to[x];
}
to[x] = -INF;
}
}

void newNode(int &x , int fa , int v)
{
if(top != -1)
x = del[top--];
else x = ++size;
ch[x][0] = ch[x][1] = 0;
pre[x] = fa;
val[x] = v , sz[x] = 1;
sum[x] = ml[x] = mr[x] = mm[x] = val[x];
rev[x] = 0 , to[x] = -INF;
}

void build(int &x , int l , int r , int fa)
{
if(l>r) return;
int m=(l+r)>>1;
newNode(x , fa , a[m]);
build(ls , l , m-1 , x);
build(rs , m+1 , r , x);
push_up(x);
}

void init(int n)
{
/*****因为所有点的最终叶子节点都下标设为了0,所以0上的数据要不影响整棵树*****/
sz[0] = sum[0] = ch[0][0] = ch[0][1] = val[0] = pre[0] = 0;
to[0] = ml[0] = mr[0] = mm[0] = -INF;
rev[0] = 0;
top = -1 , rt = size = 0;
newNode(rt , 0 , -INF);
newNode(ch[rt][1] , rt , -INF);
build(ch[ch[rt][1]][0] , 1 , n , ch[rt][1]);
push_up(ch[rt][1]);
push_up(rt);
}

void Rotate(int x , int f)
{
int y=pre[x] , z=pre[y];
/**y要旋转到下方,下传lazy标记**/
push_down(y);
ch[y][!f] = ch[x][f] , pre[ch[x][f]] = y;
ch[x][f] = y , pre[y] = x;
ch[z][ch[z][1]==y] = x , pre[x]=z;
push_up(y);
push_up(x);
}

void Splay(int x , int goal)
{
while(pre[x] != goal){
if(pre[pre[x]] == goal) Rotate(x , ch[pre[x]][0]==x);
else{
int y = pre[x] , z = pre[y];
int f = ch[z][0] == y;
if(ch[y][f] == x) Rotate(x , !f);
else Rotate(y,f);
Rotate(x , f);
}
}
push_up(x);
if(goal == 0) rt = x;
}

int Select(int pos)
{
int x = rt;
push_down(x);
while(sz[ls]+1 != pos){
if(sz[ls]+1>pos) x=ls;
else{
pos = pos-sz[ls]-1;
x = rs;
}
push_down(x);
}
return x;
}
/***从pos位置之后插入cnt个值***/
void Insert(int pos , int cnt)
{
int x = Select(pos);
Splay(x , 0);
int y = Select(pos+1);
Splay(y , x);
build(ch[y][0] , 1 , cnt , y);
/***这里build将a[1~cnt]插入到splay树中,要push_up更新***/
push_up(y);
push_up(x);
}
/***回收被删除的数的位置***/
void Recycle(int x)
{
if(x){
del[++top]=x;
Recycle(ls);
Recycle(rs);
}
}

void Delete(int s , int t)
{
int x = Select(s-1) , y = Select(t+1);
Splay(x , 0) , Splay(y , x);
Recycle(ch[y][0]);
ch[y][0] = 0;
/***这里y的左子树删除,明显子树数据改变,所以要重新push_up更新数据***/
push_up(y);
push_up(x);
}
/****将s~t区间内的所有值都修改为v****/
void update(int s , int t , int v)
{
int x = Select(s-1) , y = Select(t+1);
Splay(x , 0) , Splay(y , x);
int ptr = ch[y][0];
to[ptr]=v;
val[ptr]=v;
sum[ptr]=v*sz[ptr];
ml[ptr] = mr[ptr] = mm[ptr] = max(sum[ptr] , v);
return ;
}

void Reverse(int s , int t)
{
int x = Select(s-1) , y = Select(t+1);
Splay(x , 0) , Splay(y , x);
int ptr = ch[y][0];
rev[ptr]^=1;
swap(ml[ptr] , mr[ptr]);
}

int querySum(int s , int t)
{
int x = Select(s-1) , y =  Select(t+1);
// cout<<"x: "<<x<<" y: "<<y<<endl;
Splay(x , 0) , Splay(y , x);
return sum[ch[y][0]];
}

int queryMax()
{
int x = Select(1) , y = Select(sz[rt]);
Splay(x , 0) , Splay(y , x);
return mm[ch[y][0]];
}
}spt;
int main()
{
//  freopen("a.in" , "r" , stdin);
int n , m;
char str[20] ;
int s , t , v , pos , k;
while(~scanf("%d%d" , &n , &m))
{
for(int i=1 ; i<=n ; i++) scanf("%d" , &spt.a[i]);
spt.init(n);
/*
for(int i=0 ; i<=spt.size ; i++){
cout<<"i: "<<i<<" sum: "<<spt.sum[i]<<" l: "<<spt.ch[i][0]<<" lv: "<<spt.val[spt.ch[i][0]]<<" r: "<<spt.ch[i][1]<<" rv: "<<spt.val[spt.ch[i][1]]<<endl;
}*/
for(int i=0 ; i<m ; i++){
scanf("%s" , str);
if(str[0] == 'I'){
scanf("%d%d" , &pos , &k);
for(int i=1 ; i<=k ; i++) scanf("%d" , &spt.a[i]);
spt.Insert(pos+1 , k);
}
else if(str[0]=='D'){
scanf("%d%d" , &pos , &k);
spt.Delete(pos+1 , pos+k);
}
else if(str[0] == 'M' && str[2] == 'K'){
scanf("%d%d%d" , &pos , &k , &v);
spt.update(pos+1 , pos+k , v);
}
else if(str[0] == 'R'){
scanf("%d%d" , &pos , &k);
spt.Reverse(pos+1 , pos+k);
}
else if(str[0] == 'G'){
scanf("%d%d" , &pos , &k);
printf("%d\n" , spt.querySum(pos+1 , pos+k));
}
else{
/****这里不能直接用spt.mm[rt]作为答案,因为为了方便查询,
我们增加了两个不包含在本身数组的点,直接spt.mm[rt]会把这两个点也算进来***/
printf("%d\n" , spt.queryMax());
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: