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序列操作裸题 需要 ...
随机推荐
- jBPM4工作流应用开发指南
首先十分感谢作者给我这个机会在他的作品即将问世之前做一些感想,也正好让我能在忙碌中抽空回顾一下这么多年在技术平台方面走过的路以及在Workflow方面的点点滴滴.因为本书是介绍jBPM的专业书籍,所以 ...
- Dubbo基本特性之泛化调用
Dubbo 是支持泛化调用的,什么是泛化调用呢?泛化调用的好处是什么呢,泛化调用说白一点就是服务消费者并没有服务的接口. 在<Dubbo入门-搭建一个最简单的Demo框架>一文中,我们已完 ...
- JS基础:闭包和作用域链
简介 一个定义在函数内部的函数与包含它的外部函数构成了闭包,内部函数可以访问外部函数的变量,这些变量将一直保存在内存中,直到无法再引用这个内部函数. 例如: var a = 0; function o ...
- Netstat状态分类
用netstat -an命令查看!再stat下面有一些英文,简单说一下这些英文具体都代表什么: LISTEN:(Listening for a connection.)侦听来自远方的TCP端口的连接请 ...
- 一些Gym三星单刷的比赛总结
RDC 2013, Samara SAU ACM ICPC Quarterfinal Qualification Contest G 思路卡成智障呀! Round 1:对着这个魔法阵找了半天规律,效果 ...
- 阿里服务器CentOS报错base ls command not found
第一次linux中安装jdk时,踩过的坑. 1.vi command not found ,输入任何命令都无法实现 只要原因是因为环境变量的问题,编辑profile文件没有写正确,导致在命令行下 ls ...
- codeforces——961B. Lecture Sleep
本文为博主原创文章,未经允许不得转载. 我在csdn也同步发布了此文,链接 https://blog.csdn.net/umbrellalalalala/article/details/7989196 ...
- href="#" 是什么意思?
<a href="#" onclick="process1()">开始你表演</a>作用:书签的另一种用法建立书签语法:<a na ...
- 界面渐变特效 -- CSS实现 -- 兼容IE8
特别注意:里面的RGB颜色值必须要全写,不能使用缩写.左右:background: -webkit-gradient(linear, 0 0, 0 100%, from(#80c1e7), to(#2 ...
- jq监听input-val变化事件
$('body').on('input propertychange', '.info-number-val-box', function(event) { xxxxx });