题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1500

题目链接:https://www.luogu.org/problemnew/show/P2042

Description

请写一个程序,要求维护一个数列,支持以下 6 种操作: 请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格

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

题解:

Splay模板题。

其中,关于如何搞定求区间最大连续子列和的问题,可以参考线段树的做法:UVALive 3938 - "Ray, Pass me the dishes!" - [最大连续子列和+线段树](通过分治+最大前缀和+最大后缀和共同维护得到最大连续子列和)(感慨一下,已经想不起是哪个时候做的这道题了,时光飞逝啊……)。

关于区间翻转,则是Splay老生常谈的事情了,一个 $rev$ 标记搞定。

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=5e5+; int n,m;
int a[maxn]; /******************************** splay - st ********************************/
#define Key_value ch[ch[root][1]][0]
int root,nodecnt;
int par[maxn],ch[maxn][];
int key[maxn],sum[maxn],siz[maxn];
int mxpre[maxn],mxsuf[maxn],mxsub[maxn]; //最大前缀和,最大后缀和,最大连续子列和
bool alt[maxn],rev[maxn]; //修改标记,反转标记
int pool[maxn],poolsize; //节点回收
void NewNode(int &x,int p,int k)
{
if(poolsize>) x=pool[--poolsize];
else x=++nodecnt;
par[x]=p;
ch[x][]=ch[x][]=;
key[x]=sum[x]=k;
mxpre[x]=mxsuf[x]=mxsub[x]=k;
siz[x]=;
alt[x]=rev[x]=;
}
void Update_Rev(int x)
{
if(x==) return;
swap(ch[x][],ch[x][]);
swap(mxpre[x],mxsuf[x]);
rev[x]^=;
}
void Update_Alt(int x,int val)
{
if(x==) return;
key[x]=val;
sum[x]=siz[x]*val;
mxpre[x]=mxsuf[x]=mxsub[x]=max(val,val*siz[x]);
alt[x]=;
}
void Pushup(int x)
{
int ls=ch[x][],rs=ch[x][];
siz[x]=siz[ls]+siz[rs]+;
sum[x]=sum[ls]+sum[rs]+key[x];
mxpre[x]=max(mxpre[ls],sum[ls]+key[x]+max(,mxpre[rs]));
mxsuf[x]=max(mxsuf[rs],max(,mxsuf[ls])+key[x]+sum[rs]);
mxsub[x]=max(max(mxsub[ls],mxsub[rs]),max(,mxsuf[ls])+key[x]+max(,mxpre[rs]));
}
void Pushdown(int x)
{
if(rev[x])
{
Update_Rev(ch[x][]);
Update_Rev(ch[x][]);
rev[x]=;
}
if(alt[x])
{
Update_Alt(ch[x][],key[x]);
Update_Alt(ch[x][],key[x]);
alt[x]=;
}
}
void Rotate(int x,int type) //旋转,0为左旋zag,1为右旋zig
{
int y=par[x];
ch[y][!type]=ch[x][type]; par[ch[x][type]]=y;
if(par[y]) ch[par[y]][(ch[par[y]][]==y)]=x;
par[x]=par[y];
ch[x][type]=y; par[y]=x;
Pushup(y); Pushup(x);
}
void Splay(int x,int goal)
{
while(par[x]!=goal)
{
if(par[par[x]]==goal) Rotate(x,ch[par[x]][]==x); //左孩子zig,右孩子zag
else
{
int y=par[x];
int type=(ch[par[y]][]==y); //type=0,y是右孩子;type=1,y是左孩子
if(ch[y][type]==x)
{
Rotate(x,!type);
Rotate(x,type);
}
else
{
Rotate(y,type);
Rotate(x,type);
}
}
}
if(goal==) root=x;
}
int Get_Kth(int x,int k) //得到第k个节点
{
Pushdown(x);
int t=siz[ch[x][]]+;
if(t==k) return x;
if(t>k) return Get_Kth(ch[x][],k);
else return Get_Kth(ch[x][],k-t);
}
void Build(int &x,int l,int r,int par) //建树,先建立中间结点,再建两端的方法
{
if(l>r) return;
int mid=(l+r)/;
NewNode(x,par,a[mid]);
Build(ch[x][],l,mid-,x);
Build(ch[x][],mid+,r,x);
Pushup(x);
}
void Init() //初始化,前后各加一个空节点
{
root=nodecnt=poolsize=;
par[]=ch[][]=ch[][]=;
key[]=sum[]=siz[]=;
alt[]=rev[]=;
mxpre[]=mxsuf[]=mxsub[]=-INF;
NewNode(root,,-INF); //头部加入一个空位
NewNode(ch[root][],root,-INF); //尾部加入一个空位
Build(Key_value,,n,ch[root][]);
Pushup(ch[root][]);
Pushup(root);
} void Insert(int p,int tot)
{
for(int i=;i<=tot;i++) scanf("%d",&a[i]);
Splay(Get_Kth(root,p++),); //p伸展到根
Splay(Get_Kth(root,p++),root); //p的后继p+1伸展到根的右孩子
Build(Key_value,,tot,ch[root][]);
Pushup(ch[root][]);
Pushup(root);
} void Collect(int x) //回收节点x统领的子树
{
if(x==) return;
pool[poolsize++]=x;
Collect(ch[x][]);
Collect(ch[x][]);
}
void Delete(int p,int tot)
{
Splay(Get_Kth(root,p-+),); //伸展到根
Splay(Get_Kth(root,p+tot+),root); //伸展到根的右孩子
Collect(Key_value);
par[Key_value]=;
Key_value=;
Pushup(ch[root][]);
Pushup(root);
} void Alter(int p,int tot,int c) //修改[p,p+tot)为k
{
Splay(Get_Kth(root,p-+),); //伸展到根
Splay(Get_Kth(root,p+tot+),root); //伸展到根的右孩子
Update_Alt(Key_value,c);
Pushup(ch[root][]);
Pushup(root);
} void Reverse(int p,int tot) //反转[p,p+tot)区间
{
Splay(Get_Kth(root,p-+),);
Splay(Get_Kth(root,p+tot+),root);
Update_Rev(Key_value);
Pushup(ch[root][]);
Pushup(root);
} int Get_Sum(int p,int tot)
{
Splay(Get_Kth(root,p-+),);
Splay(Get_Kth(root,p+tot+),root);
return sum[Key_value];
} int Get_MaxSub(int p,int tot)
{
Splay(Get_Kth(root,p-+),);
Splay(Get_Kth(root,p+tot+),root);
return mxsub[Key_value];
}
/******************************** splay - ed ********************************/ int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++) scanf("%d",&a[i]);
Init(); char op[];
int pos,tot,c;
while(m--)
{
scanf("%s",op);
switch(op[]&op[]|op[])
{
case ('I'&'N'|'S'):
scanf("%d%d",&pos,&tot);
Insert(pos,tot);
break;
case ('D'&'E'|'L'):
scanf("%d%d",&pos,&tot);
Delete(pos,tot);
break;
case ('M'&'A'|'K'):
scanf("%d%d%d",&pos,&tot,&c);
Alter(pos,tot,c);
break;
case ('R'&'E'|'V'):
scanf("%d%d",&pos,&tot);
Reverse(pos,tot);
break;
case ('G'&'E'|'T'):
scanf("%d%d",&pos,&tot);
printf("%d\n",Get_Sum(pos,tot));
break;
case ('M'&'A'|'X'):
printf("%d\n",Get_MaxSub(,siz[root]-));
break;
}
}
}

BZOJ 1500/Luogu 2042 - 维修数列 - [NOI2005][Splay]的更多相关文章

  1. [bzoj1500 维修数列](NOI2005) (splay)

    真的是太弱了TAT...光是把代码码出来就花了3h..还调了快1h才弄完T_T 号称考你会不会splay(当然通过条件是1h内AC..吓傻)... 黄学长的题解:http://hzwer.com/28 ...

  2. bzoj 1500 [NOI 2005] 维修数列

    题目大意不多说了 貌似每个苦逼的acmer都要做一下这个splay树的模版题目吧 还是有很多操作的,估计够以后当模版了.... #include <cstdio> #include < ...

  3. 【BZOJ1500】【NOI2005】维修数列(Splay)

    [BZOJ1500][NOI2005]维修数列(Splay) 题面 不想再看见这种毒瘤题,自己去BZOJ看 题解 Splay良心模板题 真的很简单 我一言不发 #include<iostream ...

  4. BZOJ 1500 Luogu P2042 [NOI2005] 维护数列 (Splay)

    手动博客搬家: 本文发表于20180825 00:34:49, 原地址https://blog.csdn.net/suncongbo/article/details/82027387 题目链接: (l ...

  5. 【BZOJ】1500: [NOI2005]维修数列(splay+变态题)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1500 模板不打熟你确定考场上调试得出来? 首先有非常多的坑点...我遇到的第一个就是,如何pushu ...

  6. BZOJ 1500 维修数列【Splay】

    注意:1,内存限制,所以需要回收删除的点 2,当前节点的左连续区间和最大值=max(左子树的左连续区间和最大值,左子树的总和+当节点的值+max(右子树的左连续区间和最大值,0)):右连续区间和最大值 ...

  7. NOI2005维修数列(splay)

    题目描述: Description 请写一个程序,要求维护一个数列,支持以下 6 种操作: 请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格 Input 输入的第1 行包含两个数N 和M( ...

  8. 洛谷 2042 BZOJ 1500 NOI 2005 维护数列

    [题意概述] 维护一个数列,要求支持以下6种操作: [题解] 大Boss...可以用Treap解决 需要用到垃圾回收.线性建树. #include<cstdio> #include< ...

  9. 【BZOJ1500】维修数列(splay)

    题意: 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一条命令,格式参见问题描述中的 ...

随机推荐

  1. 简单的redis测试

    //这个方法会多一次 public function testRedisList(){ $num = 10; $user_id = uniqid(); //直接链接本地的redis $redis = ...

  2. JS前台效果

    最新的在上面 2014年3月3日14:46:46 百分比思路 function fixWidth(percent) { return document.body.clientWidth * perce ...

  3. 如何查看Apache的连接数和当前连接数

    查看Apache的连接数和当前的连接数以及IP访问次数,下面有个不错的示例,大家可以参考下,希望对大家解决问题有所帮助 查看了连接数和当前的连接数 复制代码 代码如下: netstat -ant | ...

  4. golang----GC的实现原理

    Golang从1.5开始引入了三色GC, 经过多次改进, 当前的1.9版本的GC停顿时间已经可以做到极短.停顿时间的减少意味着"最大响应时间"的缩短, 这也让go更适合编写网络服务 ...

  5. ASP.NET CORE的H5上传

    做的CORE项目中用到H5上传,把以前的MVC代码复制过来得修改一下才能用在.NET CORE中

  6. Atitit 纯java项目的提升进度大法---通用json dsl接口

    Atitit 纯java项目的提升进度大法---通用json dsl接口 1. Json dsl接口1 1.1. Url:  http://aaa.com/api_jsondsl?dsl={}1 1. ...

  7. 通用返回XML格式结果

    public class ResultModel { public string OrderCode { get; set; } public string Message { get; set; } ...

  8. [Big Data - Kafka] Kafka剖析(一):Kafka背景及架构介绍

    Kafka是由LinkedIn开发的一个分布式的消息系统,使用Scala编写,它以可水平扩展和高吞吐率而被广泛使用.目前越来越多的开源分布式处理系统如Cloudera.Apache Storm.Spa ...

  9. JVM 内部原理(一)— 概述

    JVM 内部原理(一)- 概述 介绍 版本:Java SE 7 图中显示组件将会从两个方面分别解释.第一部分涵盖线程独有的组件,第二部分涵盖独立于线程的组件(即线程共享组件). 目录 线程独享(Thr ...

  10. AllPay(欧付宝)支付接口集成

    AllPay,http://www.allpay.com.tw/,欧付宝是台湾知名的第三方支付公司,拥有丰富的支付模式(支持和支付宝.财付通),只需要一次对接,各种支付模式均可使用. 接口编写SDK: ...