您的位置:首页 > 其它

NOI2005 维修数列(综合包括求区间的最大值)---Splay

2015-05-31 09:50 435 查看
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string.h>
#include <queue>
#define N 500010     //数组要定大点
#define inf 1<<30
using namespace std;
int pre
, key
, ch
[2], root, tot, rev
, same
, size
, sum1
; //rev表示旋转标记,same表示数值改变的标记
int n, m, max1, s1, a
, lmax
, rmax
, mmax
, s
, tot2;  //lmax指从左边开始最大值, mmax指这个区间连续的最大值, 数组s用来回收空间
/*
区间最大和,可能是左子树的最大和,右子树的最大和,左子树的右端+节点+右子树的左端
伸展树里的节点所表示的树可以看做是一个区间,最左边和最右边分别是区间的两个端点
*/
void update(int x)
{
int j=ch[x][0], k=ch[x][1];
size[x]=size[j]+size[k]+1;
sum1[x]=sum1[j]+sum1[k]+key[x];
lmax[x]=max(lmax[j], sum1[j]+key[x]+max(0, lmax[k]));  //在这个区间内
rmax[x]=max(rmax[k], sum1[k]+key[x]+max(0, rmax[j]));
mmax[x]=max(0, rmax[j])+key[x]+max(0, lmax[k]);
mmax[x]=max(mmax[x], max(mmax[j], mmax[k]));
return ;
}
void updaterev(int x) //先处理x节点,rev[x]为1表示这个节点已经处理了(旋转)
{
if(!x)return ;
swap(ch[x][0], ch[x][1]);
swap(lmax[x], rmax[x]); //翻转时左右区间也交换!
rev[x]^=1;
return ;
}
void updatesame(int x, int k)
{
if(!x)return ;
key[x]=k;
sum1[x]=size[x]*k;
lmax[x]=rmax[x]=mmax[x]=max(k, k*size[x]);    //判断正负的最大值
same[x]=1;
return ;
}

void pushdown(int x)
{
if(rev[x])
{
updaterev(ch[x][0]);
updaterev(ch[x][1]);
rev[x]=0;
}
if(same[x])
{
updatesame(ch[x][0], key[x]);
updatesame(ch[x][1], key[x]);
same[x]=0;
}
return ;
}
void newnode(int &r, int father, int k)
{
if(tot2)  //用数组s回收来的空间新建,否则会TLE
r=s[tot2--];
else r=++tot;
pre[r]=father;
size[r]=1;
same[r]=rev[r]=0;
ch[r][0]=ch[r][1]=0;
key[r]=lmax[r]=rmax[r]=mmax[r]=sum1[r]=k;
return ;
}
void build(int l, int r, int &k, int father)
{
if(l>r)return ;
int mid=(l+r)>>1;
newnode(k, father, a[mid]);
build(l, mid-1, ch[k][0], k);
build(mid+1, r, ch[k][1], k);
update(k);
return ;
}
void init()
{
pre[0]=rev[0]=same[0]=key[0]=ch[0][0]=ch[0][1]=root=tot=tot2=size[0]=0;
lmax[0]=rmax[0]=mmax[0]=-inf;  //这里要注意初始化
newnode(root, 0, -1);
newnode(ch[root][1], root, -1);
update(root);
build(1, n, ch[ch[root][1]][0], ch[root][1]);
update(ch[root][1]);
update(root);
return ;
}
void rotate(int x, int kind)
{
int k=pre[x];
pushdown(k);
pushdown(x);
ch[k][!kind]=ch[x][kind];
pre[ch[x][kind]]=k;
ch[x][kind]=k;
if(pre[k])
ch[pre[k]][ch[pre[k]][1]==k]=x;
pre[x]=pre[k];
pre[k]=x;
update(k);
return ;
}
void Splay(int x, int goal)
{
int k, g, h;
pushdown(x);
while(pre[x]!=goal)
{
k=pre[x];
if(pre[k]==goal)
{
rotate(x, ch[k][0]==x);
}
else
{
g=(ch[k][0]==x?0:1);
h=(ch[pre[k]][0]==k?0:1);
if(g==h)
{
rotate(k, !g);
rotate(x, !g);
}
else
{
rotate(x, !g);
rotate(x, g);
}
}
}
if(!goal)root=x;
update(x);
return ;
}
int select(int k, int x)
{
pushdown(x);
if(size[ch[x][0]]+1==k)
return x;
else if(size[ch[x][0]]+1>k)
return select(k, ch[x][0]);
else return select(k-size[ch[x][0]]-1, ch[x][1]);
}
int getmin(int r)
{
int s=r;
pushdown(r);
while(r)
{
s=r;
r=ch[r][0];
pushdown(r);
}
return s;
}
void insert(int k, int num)
{
int j, g;
j=select(k+1, root);
Splay(j, 0);
g=getmin(ch[root][1]);
Splay(g, root);
build(1, num, ch[g][0], g);
update(g);
update(j);
return ;
}
void erase(int r)  //回收空间
{
if(!r)return ;
s[++tot2]=r;
erase(ch[r][0]);
erase(ch[r][1]);
return ;
}

void dele(int k, int num)
{
int j, g;
j=select(k, root);
g=select(k+num+1, root);
Splay(j, 0);
Splay(g, root);
erase(ch[g][0]);
pre[ch[g][0]]=0;
ch[g][0]=0;
update(g);
update(j);
return ;
}
void change(int k, int num, int c)
{
int j, g;
j=select(k, root);
g=select(k+num+1, root);
Splay(j, 0);
Splay(g, root);
updatesame(ch[g][0], c);   //这里是updatesame,对ch[g][0]处理
update(g); //更新
update(j);
return ;
}
void reversal(int k, int num)
{
int j, g;
j=select(k, root);
g=select(k+num+1, root);
Splay(j, 0);
Splay(g, root);
updaterev(ch[g][0]);
return ;
}
int getsum(int k, int num)
{
int j, g;
j=select(k, root);
g=select(k+num+1, root);
Splay(j, 0);
Splay(g, root);
return sum1[ch[g][0]];
}
int getmax(int r)
{
int s=r;
pushdown(r);
while(r)
{
s=r;
r=ch[r][1];
pushdown(r);
}
return s;
}
int maxsum()
{
int j, g;
j=getmin(root);
g=getmax(root);
Splay(j, 0);
Splay(g, root);
return mmax[ch[g][0]];
}
int main()
{
int t, j, k, g;
char p[20];
while(scanf("%d%d", &n, &m)!=EOF)
{
for(t=1; t<=n; ++t)
scanf("%d", a+t);
init();
while(m--)
{
scanf("%s", p);
if(strcmp(p, "INSERT")==0)
{
scanf("%d%d", &j, &k);
for(t=1; t<=k; ++t)
scanf("%d", a+t);
insert(j, k);
continue;
}
if(strcmp(p, "DELETE")==0)
{
scanf("%d%d", &j, &k);
dele(j, k);
continue;
}
if(strcmp(p, "MAKE-SAME")==0)
{
scanf("%d%d%d", &j, &k, &g);
change(j, k, g);
continue;
}
if(strcmp(p, "REVERSE")==0)
{
scanf("%d%d", &j, &k);
reversal(j, k);
continue;
}
if(strcmp(p, "GET-SUM")==0)
{
scanf("%d%d", &j, &k);
printf("%d\n", getsum(j, k));
continue;
}
if(strcmp(p, "MAX-SUM")==0)
{
printf("%d\n", maxsum());
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: