BZOJ1500 [NOI2005]维修数列-fhq_Treap
反正是道平衡树,就拿 fhq_Treap 写了写...
这道题思路基本是围绕“用 Treap 维护中序遍历” 和 中序遍历的性质 来进行的操作
所以就可以类比线段树进行一些操作
1. 建树 & 插入
这题也要用到笛卡尔树的建树方式,假的 O(n) 真是相当快啊
inline int build(int r) {
top = 0;
register int tmp = newnode(a[1]);
stk[++top] = tmp;
for(int i = 2; i <= r; ++i) {
int last = 0, cur = newnode(a[i]);
while(top and t[stk[top]].prio > t[cur].prio) {
pushup(stk[top]);
last = stk[top];
stk[top--] = 0;
}
t[cur].ch[0] = last;
pushup(cur);
if(top) {
t[stk[top]].ch[1] = cur;
pushup(stk[top]);
}
stk[++top] = cur;
}
while(top) pushup(stk[top--]);
return stk[1];
}
在本题中呢,由于插入的值不是一个一个给出的而是给出序列,故应先建出一棵小 Treap 再合并过去
在这里也要用到上面提到的方式来建这棵小树
inline void Insert(int pos, int tot) {
int newrt = build(tot);
pair<int, int> x = Split(Root, pos);
Root = Merge(Merge(x.first, newrt), x.second);
return;
}
2.删除
此题的删除也是删除一段序列,直接 Split 出来即可
不过这里注意到任何时刻数列中最多含有 5e5 个数,多写一个内存回收就好了
inline int Malloc(){
register int x;
return (!delpool.empty()) ? (t[x = delpool.front()].clear(), delpool.pop(), x) : (++poolcur);
}
inline int newnode(int val) {
register int cur = Malloc();
t[cur].val = t[cur].sum = t[cur].prtmx = val;
t[cur].lmx = t[cur].rmx = max(0, val);
t[cur].prio = rand();
t[cur].siz = 1;
return cur;
}
void Recycle(int cur) {
if(!cur) return;
if(lson) Recycle(lson);
delpool.push(cur);
if(rson) Recycle(rson);
return;
}
inline void Remove(int pos, int tot) {
pair<int, int> x = Split(Root, pos + tot - 1);
pair<int, int> y = Split(x.first, pos - 1);
Recycle(y.second);
Root = Merge(y.first, x.second);
return;
}
觉得递归不优美的可以手写栈模拟
3.区间修改
打标记
inline void cover(int pos, int tot, int val) {
pair<int, int> x = Split(Root, pos + tot - 1);
pair<int, int> y = Split(x.first, pos - 1);
t[y.second].val = t[y.second].cvr = val;
t[y.second].sum = val * t[y.second].siz;
t[y.second].lmx = t[y.second].rmx = max(0, t[y.second].sum);
t[y.second].prtmx = max(t[y.second].val, t[y.second].sum);
t[y.second].rvrs = false;
Root = Merge(Merge(y.first, y.second), x.second);
return;
}
4.翻转区间
比较基础的操作
inline void Reverse(int pos, int tot) {
pair<int, int> x = Split(Root, pos + tot - 1);
pair<int, int> y = Split(x.first, pos - 1);
t[y.second].rvrs ^= 1;
swap(t[y.second].lmx, t[y.second].rmx);
swap(t[y.second].ch[0], t[y.second].ch[1]);
Root = Merge(Merge(y.first, y.second), x.second);
return;
}
5.求和 & 最大子段和
这里一开始不敢这么写,其实是可以的
在提取一个区间的过程中,是在不断 pushup 和 pushdown 的,故提取/合并后并不会出什么差错
像线段树一样维护,一些维护的的值在 Reverse 后注意更新
inline void rvrs(int cur) {
swap(lson, rson);
swap(t[cur].lmx, t[cur].rmx);
t[cur].rvrs ^= 1;
return;
}
inline void cvr(int cur, int val) {
t[cur].cvr = t[cur].val = val;
t[cur].sum = t[cur].siz * val;
t[cur].prtmx = max(t[cur].val, t[cur].sum);
t[cur].lmx = t[cur].rmx = max(0, t[cur].sum);
return;
}
inline void pushup(int cur) {
t[cur].siz = t[lson].siz + t[rson].siz + 1;
t[cur].sum = t[cur].val + t[lson].sum + t[rson].sum;
t[cur].lmx = max(0, max(t[lson].lmx, t[lson].sum + t[rson].lmx + t[cur].val));
t[cur].rmx = max(0, max(t[rson].rmx, t[rson].sum + t[lson].rmx + t[cur].val));
t[cur].prtmx = max(t[cur].val, t[lson].rmx + t[rson].lmx + t[cur].val);
if(lson) t[cur].prtmx = max(t[cur].prtmx, t[lson].prtmx);
if(rson) t[cur].prtmx = max(t[cur].prtmx, t[rson].prtmx);
return;
}
inline void pushdown(int cur) {
if(t[cur].rvrs) {
if(lson) rvrs(lson);
if(rson) rvrs(rson);
}
if(t[cur].cvr != inf) {
if(lson) cvr(lson, t[cur].cvr);
if(rson) cvr(rson, t[cur].cvr);
}
t[cur].rvrs = false;
t[cur].cvr = inf;
return;
}
完整的代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<cstdio>
#include<cmath>
#include<queue>
#include<ctime>
#define lson t[cur].ch[0]
#define rson t[cur].ch[1]
using namespace std; const int MAXN = 500010, inf = 2333; struct Node{
int ch[2], siz, val, prio, lmx, rmx, sum, prtmx;
int cvr;
bool rvrs;
Node(){ch[0] = ch[1] = siz = val = sum = 0; cvr = inf; rvrs = false;}
void clear(){
ch[0] = ch[1] = siz = val = sum = 0;
cvr = inf;
rvrs = false;
return;
}
}t[MAXN];
int n, m, poolcur, Root;
int a[MAXN], stk[MAXN], top;
queue<int> delpool;
char que[20]; inline int Malloc(){
register int x;
return (!delpool.empty()) ? (t[x = delpool.front()].clear(), delpool.pop(), x) : (++poolcur);
}
inline int newnode(int val) {
register int cur = Malloc();
t[cur].val = t[cur].sum = t[cur].prtmx = val;
t[cur].lmx = t[cur].rmx = max(0, val);
t[cur].prio = rand();
t[cur].siz = 1;
return cur;
}
inline void pushup(int cur) {
t[cur].siz = t[lson].siz + t[rson].siz + 1;
t[cur].sum = t[cur].val + t[lson].sum + t[rson].sum;
t[cur].lmx = max(0, max(t[lson].lmx, t[lson].sum + t[rson].lmx + t[cur].val));
t[cur].rmx = max(0, max(t[rson].rmx, t[rson].sum + t[lson].rmx + t[cur].val));
t[cur].prtmx = max(t[cur].val, t[lson].rmx + t[rson].lmx + t[cur].val);
if(lson) t[cur].prtmx = max(t[cur].prtmx, t[lson].prtmx);
if(rson) t[cur].prtmx = max(t[cur].prtmx, t[rson].prtmx);
return;
}
inline void rvrs(int cur) {
swap(lson, rson);
swap(t[cur].lmx, t[cur].rmx);
t[cur].rvrs ^= 1;
return;
}
inline void cvr(int cur, int val) {
t[cur].cvr = t[cur].val = val;
t[cur].sum = t[cur].siz * val;
t[cur].prtmx = max(t[cur].val, t[cur].sum);
t[cur].lmx = t[cur].rmx = max(0, t[cur].sum);
return;
}
inline void pushdown(int cur) {
if(t[cur].rvrs) {
if(lson) rvrs(lson);
if(rson) rvrs(rson);
}
if(t[cur].cvr != inf) {
if(lson) cvr(lson, t[cur].cvr);
if(rson) cvr(rson, t[cur].cvr);
}
t[cur].rvrs = false;
t[cur].cvr = inf;
return;
}
inline int build(int r) {
top = 0;
register int tmp = newnode(a[1]);
stk[++top] = tmp;
for(int i = 2; i <= r; ++i) {
int last = 0, cur = newnode(a[i]);
while(top and t[stk[top]].prio > t[cur].prio) {
pushup(stk[top]);
last = stk[top];
stk[top--] = 0;
}
t[cur].ch[0] = last;
pushup(cur);
if(top) {
t[stk[top]].ch[1] = cur;
pushup(stk[top]);
}
stk[++top] = cur;
}
while(top) pushup(stk[top--]);
return stk[1];
}
pair<int, int> Split(int cur, int k) {
if(!cur or !k) return make_pair(0, cur);
pushdown(cur);
pair<int, int> res;
if(t[lson].siz >= k) {
res = Split(lson, k);
lson = res.second;
pushup(cur);
res.second = cur;
} else {
res = Split(rson, k - t[lson].siz - 1);
rson = res.first;
pushup(cur);
res.first = cur;
}
return res;
}
int Merge(int x, int y) {
if(x) pushdown(x); if(y) pushdown(y);
if(!x) return y; if(!y) return x;
if(t[x].prio < t[y].prio) {
t[x].ch[1] = Merge(t[x].ch[1], y);
pushup(x);
return x;
} else {
t[y].ch[0] = Merge(x, t[y].ch[0]);
pushup(y);
return y;
}
}
void Recycle(int cur) {
if(!cur) return;
if(lson) Recycle(lson);
delpool.push(cur);
if(rson) Recycle(rson);
return;
}
inline void Insert(int pos, int tot) {
int newrt = build(tot);
pair<int, int> x = Split(Root, pos);
Root = Merge(Merge(x.first, newrt), x.second);
return;
}
inline void Remove(int pos, int tot) {
pair<int, int> x = Split(Root, pos + tot - 1);
pair<int, int> y = Split(x.first, pos - 1);
Recycle(y.second);
Root = Merge(y.first, x.second);
return;
}
inline void Reverse(int pos, int tot) {
pair<int, int> x = Split(Root, pos + tot - 1);
pair<int, int> y = Split(x.first, pos - 1);
t[y.second].rvrs ^= 1;
swap(t[y.second].lmx, t[y.second].rmx);
swap(t[y.second].ch[0], t[y.second].ch[1]);
Root = Merge(Merge(y.first, y.second), x.second);
return;
}
inline void cover(int pos, int tot, int val) {
pair<int, int> x = Split(Root, pos + tot - 1);
pair<int, int> y = Split(x.first, pos - 1);
t[y.second].val = t[y.second].cvr = val;
t[y.second].sum = val * t[y.second].siz;
t[y.second].lmx = t[y.second].rmx = max(0, t[y.second].sum);
t[y.second].prtmx = max(t[y.second].val, t[y.second].sum);
t[y.second].rvrs = false;
Root = Merge(Merge(y.first, y.second), x.second);
return;
}
inline int getsum(int pos, int tot) {
pair<int, int> x = Split(Root, pos + tot - 1);
pair<int, int> y = Split(x.first, pos - 1);
int ans = t[y.second].sum;
Root = Merge(Merge(y.first, y.second), x.second);
return ans;
}
void rdstr(char s[]) {
register int sz = 0;
register char c = getchar();
while(!isalpha(c) and c != '-') c = getchar();
while(isalpha(c) || (c == '-')) {
s[sz++] = c;
c = getchar();
}
return;
}
inline int rd() {
register int x = 0;
register char c = getchar();
register bool f = false;
while(!isdigit(c)) {
if(c == '-') f = true;
c = getchar();
}
while(isdigit(c)) {
x = x * 10 + (c ^ 48);
c = getchar();
}
return f ? -x : x;
} int main() {
srand(time(NULL));
n = rd(); m = rd();
for(int i = 1; i <= n; ++i) a[i] = rd();
Root = build(n);
int pos, tot, val;
while(m--) {
rdstr(que);
switch(que[0]) {
case 'I':{
pos = rd(); tot = rd();
for(int i = 1; i <= tot; ++i) a[i] = rd();
Insert(pos, tot);
break;
}
case 'D':{
pos = rd(); tot = rd();
Remove(pos, tot);
break;
}
case 'R':{
pos = rd(); tot = rd();
Reverse(pos, tot);
break;
}
case 'G':{
pos = rd(); tot = rd();
printf("%d\n", getsum(pos, tot));
break;
}
case 'M':{
if(que[2] == 'K') {
pos = rd(); tot = rd(); val = rd();
cover(pos, tot, val);
} else {
printf("%d\n", t[Root].prtmx);
}
break;
}
}
}
return 0;
}
BZOJ1500 [NOI2005]维修数列-fhq_Treap的更多相关文章
- [BZOJ1500][NOI2005]维修数列---解题报告
Portal Gun:[BZOJ1500][NOI2005]维修数列 有一段时间没写博客了,最近在刚数据结构......各种板子背得简直要起飞,题目也是一大堆做不完,这里就挑一道平衡树的题来写写好了 ...
- [BZOJ1500][NOI2005]维修数列 解题报告 Splay
Portal Gun:[BZOJ1500][NOI2005]维修数列 有一段时间没写博客了,最近在刚数据结构......各种板子背得简直要起飞,题目也是一大堆做不完,这里就挑一道平衡树的题来写写好了 ...
- bzoj千题计划221:bzoj1500: [NOI2005]维修数列(fhq treap)
http://www.lydsy.com/JudgeOnline/problem.php?id=1500 1.覆盖标记用INF表示无覆盖标记,要求可能用0覆盖 2.代表空节点的0号节点和首尾的两个虚拟 ...
- [bzoj1500][NOI2005]维修数列_非旋转Treap
维修数列 bzoj-1500 NOI-2005 题目大意:给定n个数,m个操作,支持:在指定位置插入一段数:删除一个数:区间修改:区间翻转.查询:区间和:全局最大子序列. 注释:$1\le n_{ma ...
- splay模板三合一 luogu2042 [NOI2005]维护数列/bzoj1500 [NOI2005]维修数列 | poj3580 SuperMemo | luogu3391 【模板】文艺平衡树(Splay)
先是维修数列 题解看这里,但是我写的跑得很慢 #include <iostream> #include <cstdio> using namespace std; int n, ...
- BZOJ1500[NOI2005]维修数列
Description Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一 ...
- BZOJ1500: [NOI2005]维修数列[splay ***]
1500: [NOI2005]维修数列 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 12278 Solved: 3880[Submit][Statu ...
- [bzoj1500][NOI2005]维修数列——splay
题目 题解 这道题可以说是数列问题的大BOSS,也算是这一周来学习splay等数据结构的一个总结. 我们一个一个地看这些操作. 对于操作1,我们首先建一棵子树,直接接上原树即可. 对于操作2,我们找到 ...
- BZOJ1500: [NOI2005]维修数列 [splay序列操作]【学习笔记】
以前写过这道题了,但我把以前的内容删掉了,因为现在感觉没法看 重写! 题意: 维护一个数列,支持插入一段数,删除一段数,修改一段数,翻转一段数,查询区间和,区间最大子序列 splay序列操作裸题 需要 ...
随机推荐
- 框架学习:ibatis框架的结构和分析
由于最近一段时间比较忙碌,<框架学习>系列的文章一直在搁浅着,最近开始继续这个系列的文章更新. 在上篇文章中我们说到了hibernate框架,它是一种基于JDBC的主流持久化框架,是一个优 ...
- saltstack安装部署以及简单实用
一,saltstack简介: SaltStack是一种新的基础设施管理方法开发软件,简单易部署,可伸缩的足以管理成千上万的服务器,和足够快的速度控制,与他们交流,以毫秒为单位. SaltSta ...
- 接口文档神器之apidoc
//@desn:apidoc linux环境 windows环境使用 //@desn:码字不宜,转载请注明出处 //@author:张慧源 <turing_zhy@163.com> / ...
- [转]在Windows下编译ffmpeg完全手册
本文的内容几乎全部来自于FFmpeg on Windows,但是由于国内的网络封锁,很难访问这个域名下的内容,因此我一方面按照我自己的理解和实践做了翻译,另一方面也是为了能提供一个方便的参考方法. 注 ...
- Mysql系列-数据库
一 .数据库管理软件的由来 基于我们之前所学,数据要想永久保存,都是保存于文件中,毫无疑问,一个文件仅仅只能存在于某一台机器上. 如果我们暂且忽略直接基于文件来存取数据的效率问题,并且假设程序所有的组 ...
- scala函数
1.probablePrime(6,Random) Random是scala.util._中的包 probablePrime是scala.math.BigInt._伴生对象中的方法: probable ...
- lvs与nginx区别
lvs和nginx都可以用作多机负载方案,他们各有优缺点,在生产环境中需要好好分析实际情况并加以利用. 一.lvs的优势: 1.抗负载能力强,因为lvs工作方式的逻辑是非常简单的,而且工作再网络层第4 ...
- CSS样式渐变代码,兼容IE8
background: -webkit-linear-gradient(top,#ffffff,#f5f5f5); background: -moz-linear-gradient(top,#ffff ...
- PHP 中的 __FILE__ 和__DIR__常量
__DIR__ :当前内容写在哪个文件就显示这个文件目录 __FILE__ : 当前内容写在哪个文件就显示这个文件目录+文件名 比如文件 b.php 包含如下内容: <?php $basedir ...
- C# 使用SmtpClient发送Email
使用Winfrom写的报错信息发送邮件通知. 以下主要代码 /// <summary> /// 发送邮件核心代码 /// </summary> /// <param na ...