bzoj1500 维修数列 splay

1500: [NOI2005]维修数列

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 10482  Solved: 3234
[Submit][Status][Discuss]

Description

Input

输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目。
第2行包含N个数字,描述初始时的数列。
以下M行,每行一条命令,格式参见问题描述中的表格。
任何时刻数列中最多含有500 000个数,数列中任何一个数字均在[-1 000, 1 000]内。
插入的数字总数不超过4 000 000个,输入文件大小不超过20MBytes。

Output

对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字)占一行。

Sample Input

9 8
2 -6 3 5 1 -5 -3 6 3
GET-SUM 5 4
MAX-SUM
INSERT 8 3 -5 7 2
DELETE 12 1
MAKE-SAME 3 3 2
REVERSE 3 6
GET-SUM 5 4
MAX-SUM

Sample Output

-1
10
1
10

HINT

终于过了,原来是维护最大子序列合并的时候写错了。。。应该是当前结点最大子序列和等于max(左子结点最大子序列,和右子结点最大子序列,横跨左右的最大子序列和),我居然写成了max(包括左端点的最大子序列,包括右端点的最大子序列,.....)。。。。。

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))
#define key_val ch[ch[rt][1]][0]

using namespace std;

typedef long long ll;
const int maxn=500100;
const int INF=1e9+10;
const ll MOD=1e9+7;

int N,M;
int a[maxn];
char op[20];int pos,n;
int c[maxn];

int pre[maxn],sz[maxn],ch[maxn][2],rt,tot1;
int s[maxn],tot2;
int sum[maxn],val[maxn];
int ls[maxn],rs[maxn],ms[maxn];
int cov[maxn],rev[maxn];

int newnode(int &r,int fa,int k)
{
    if(tot2) r=s[tot2--];
    else r=++tot1;
    pre[r]=fa;val[r]=k;
    sz[r]=1;MS0(ch[r]);
    sum[r]=k;
    cov[r]=rev[r]=0;
    ls[r]=ms[r]=rs[r]=k;
}

void update_rev(int r)
{
    if(r==0) return;
    rev[r]^=1;
    swap(ch[r][0],ch[r][1]);
    swap(ls[r],rs[r]);
}

void update_cov(int r,int c)
{
    if(r==0) return;
    cov[r]=1;
    sum[r]=c*sz[r];
    val[r]=c;
    ls[r]=rs[r]=ms[r]=max(c,c*sz[r]);
}

void down(int r)
{
    if(rev[r]){
        update_rev(ch[r][0]);
        update_rev(ch[r][1]);
        rev[r]=0;
    }
    if(cov[r]){
        update_cov(ch[r][0],val[r]);
        update_cov(ch[r][1],val[r]);
        cov[r]=0;
    }
}

void up(int r)
{
    sz[r]=sz[ch[r][0]]+sz[ch[r][1]]+1;
    sum[r]=sum[ch[r][0]]+sum[ch[r][1]]+val[r];
    ls[r]=max(ls[ch[r][0]],sum[ch[r][0]]+val[r]+max(0,ls[ch[r][1]]));
    rs[r]=max(rs[ch[r][1]],sum[ch[r][1]]+val[r]+max(0,rs[ch[r][0]]));
    ms[r]=val[r]+max(rs[ch[r][0]],0)+max(ls[ch[r][1]],0);
    ms[r]=max(ms[r],max(ms[ch[r][0]],ms[ch[r][1]]));
}

void rot(int x,int kind)
{
    int y=pre[x];
    down(y);down(x);
    ch[y][kind^1]=ch[x][kind];
    pre[ch[x][kind]]=y;
    if(pre[y]) ch[pre[y]][ch[pre[y]][1]==y]=x;
    pre[x]=pre[y];
    ch[x][kind]=y;
    pre[y]=x;
    up(y);
}

void splay(int x,int goal)
{
    down(x);
    while(pre[x]!=goal){
        if(pre[pre[x]]==goal) rot(x,ch[pre[x]][0]==x);
        else{
            int y=pre[x],z=pre[y];
            int kind=ch[y][0]==x,one=0;
            if(ch[y][0]==x&&ch[z][0]==y) one=1;
            if(ch[y][1]==x&&ch[z][1]==y) one=1;
            if(one) rot(y,kind),rot(x,kind);
            else rot(x,kind),rot(x,kind^1);
        }
    }
    if(goal==0) rt=x;
    up(x);
}

void rto(int k,int goal)
{
    int r=rt;k++;
    while(k!=sz[ch[r][0]]+1){
        down(r);
        if(k<sz[ch[r][0]]+1) r=ch[r][0];
        else k-=sz[ch[r][0]]+1,r=ch[r][1];
    }
    splay(r,goal);
}

void build(int &x,int l,int r,int fa,int *a)
{
    if(l>r) return;
    int m=(l+r)>>1;
    newnode(x,fa,a[m]);
    build(ch[x][0],l,m-1,x,a);
    build(ch[x][1],m+1,r,x,a);
    up(x);
}

void Init()
{
    pre[0]=sz[0]=s[0]=0;MS0(ch[0]);rt=tot1=tot2=0;
    sum[0]=val[0]=cov[0]=rev[0]=0;
    ls[0]=rs[0]=ms[0]=-INF;
    newnode(rt,0,-1);
    newnode(ch[rt][1],rt,-1);
    sz[rt]=2;
    build(key_val,1,N,ch[rt][1],a);
    up(ch[rt][1]);up(rt);
}

void Rev(int l,int r)
{
    rto(l-1,0);
    rto(r+1,rt);
    down(rt);down(ch[rt][1]);
    update_rev(key_val);
    up(ch[rt][1]);up(rt);
}

void Cov(int l,int r,int c)
{
    rto(l-1,0);
    rto(r+1,rt);
    down(rt);down(ch[rt][1]);
    update_cov(key_val,c);
    up(ch[rt][1]);up(rt);
}

void Erase(int r)
{
    if(r==0) return;
    s[++tot2]=r;
    Erase(ch[r][0]);
    Erase(ch[r][1]);
}

void Del(int l,int r)
{
    rto(l-1,0);
    rto(r+1,rt);
    down(rt);down(ch[rt][1]);
    Erase(key_val);
    key_val=0;
    up(ch[rt][1]);up(rt);
}

void Insert(int pos,int n)
{
    rto(pos,0);
    rto(pos+1,rt);
    down(rt);down(ch[rt][1]);
    build(key_val,1,n,ch[rt][1],c);
    up(ch[rt][1]);up(rt);
}

int Sum(int l,int r)
{
    if(l>r) return 0;
    rto(l-1,0);
    rto(r+1,rt);
    down(rt);down(ch[rt][1]);
    return sum[key_val];
}

int Max_sum()
{
    int l=1,r=sz[rt]-2;
    if(l>r) return 0;
    rto(l-1,0);
    rto(r+1,rt);
    down(rt);down(ch[rt][1]);
    return ms[key_val];
}

int main()
{
    freopen("in.txt","r",stdin);
    while(~scanf("%d%d",&N,&M)){
        REP(i,1,N) scanf("%d",&a[i]);
        Init();
        //out();
        REP(i,1,M){
            scanf("%s",&op);
            if(op[0]==‘I‘){
                scanf("%d%d",&pos,&n);
                REP(j,1,n) scanf("%d",&c[j]);
                Insert(pos,n);
            }
            else if(op[0]==‘D‘){
                scanf("%d%d",&pos,&n);
                Del(pos,pos+n-1);
            }
            else if(op[0]==‘M‘&&op[2]==‘K‘){
                scanf("%d%d%d",&pos,&n,&c[0]);
                Cov(pos,pos+n-1,c[0]);
            }
            else if(op[0]==‘R‘){
                scanf("%d%d",&pos,&n);
                Rev(pos,pos+n-1);
            }
            else if(op[0]==‘G‘){
                scanf("%d%d",&pos,&n);
                printf("%d\n",Sum(pos,pos+n-1));
            }
            else printf("%d\n",Max_sum());
        }
    }
    return 0;
}

时间: 2024-12-28 01:05:26

bzoj1500 维修数列 splay的相关文章

BZOJ1500: [NOI2005]维修数列[splay ***]

1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 12278  Solved: 3880[Submit][Status][Discuss] Description Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一条命令,格式参见问题描述中的表格.任何时刻数列中最多含有500 000个数,

BZOJ1500 维修数列

1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MB Description Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一条命令,格式参见问题描述中的表格.任何时刻数列中最多含有500 000个数,数列中任何一个数字均在[-1 000, 1 000]内.插入的数字总数不超过4 000 000个,输入文

BZOJ 1500: [NOI2005]维修数列( splay )

splay..... ------------------------------------------------------------------------ #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<queue> #define rep( i , n ) for( int i = 0 ; i < n ; ++

【bzoj1500】维修数列——splay

splay的高级题目,有splay的全部操作,然而本蒟蒻竟不自量力地把这道题作为splay的入门题,然后就学(mi)习(man)了一个星期-- 第一次是对着cyc的模版码的,万分感谢>< 第二次就自己码了一个小时(弱......) 就作为一个splay学习的模版吧! #include<cstdio> #include<cstring> #include<iostream> #include<queue> const int maxn=5e5+10

[bzoj1500][NOI2005 维修数列] (splay区间操作)

Description Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目. 第2行包含N个数字,描述初始时的数列. 以下M行,每行一条命令,格式参见问题描述中的表格. 任何时刻数列中最多含有500 000个数,数列中任何一个数字均在[-1 000, 1 000]内. 插入的数字总数不超过4 000 000个,输入文件大小不超过20MBytes. Output 对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次

【bzoj1500 维修数列】(NOI2005)

真的是太弱了TAT...光是把代码码出来就花了3h..还调了快1h才弄完T_T 号称考你会不会splay(当然通过条件是1h内AC..吓傻)... 黄学长的题解:http://hzwer.com/2841.html 当然了蒟蒻的splay模板全部都是借(抄)鉴(袭)黄学长的.... 主要是注意任何对子树的修改一定要记得pushup一定要记得pushup一定要记得pushup...计算最大子段和和bzoj1858一个姿势,就是维护子树的最大子段和,从左和从右开始的最大子段和(当然了平衡树和线段树在

HYSBZ 1500 [NOI2005]维修数列 splay

解题思路:终于把这道splay神题A掉了,splay专题也算是告一段落了,这个题主要的坑点,还是旋转和区间合并结合. 解题代码: 1 // File Name: hysbz1500.cpp 2 // Author: darkdream 3 // Created Time: 2015年04月10日 星期五 10时41分03秒 4 5 #include<vector> 6 #include<list> 7 #include<map> 8 #include<set>

BZOJ 1500 NOI 2005 维修数列 Splay

题意:见下图 传说级别的NOI数据结构神题,像我这种弱渣花了一下午的时间才A掉,最后发现竟然是边界值的问题没处理好.. 这个题对Splay的所有操作基本是全了. 插入:新建一颗Splay Tree,然后把对应节点Splay到根的右儿子上,再把新建的树连上. 删除:把要删除的区间Splay到根的右儿子的左儿子上,递归free掉.(这里可以用数组优化,可以避免递归free节省时间) 修改,翻转:打标记,在需要的时候下传标记,和线段树差不多,翻转标记下传时,要将左右儿子的左右儿子分别交换. 求和:维护

Splay必做题 [NOI2005]维修数列

1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 6577  Solved: 1978[Submit][Status] Description Input 输入文件的第1行包含两个数N和M,N表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一条命令,格式参见问题描述中的表格. Output 对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印