NOI2005 维护数列
我还是没有逃过在这道题上debug好久的命运……
我是使用\(fhq-treap\)来做的这道题。写的时候写的挺爽的……调的时候真难受。
首先我们先来说说咋做吧。前5个操作对于\(fhq-treap\)来说不在话下,只要多打两个标记就可以了。但是如何求最大子段和?
我们一般只会想到一种\(O(n)\)的做法吧。但是这样必然超时。其实这个还有另一种分治的做法,我们在线段树上可能会经常用到,就是维护每个节点从左,右,和在它内部的连续最大字段和。之后我们通过左右儿子来进行合并即可。有一道题传送门(SDOI2011 染色) 就用到了这种做法,不过维护的不是最大字段和(滑稽)
于是乎我们再打三个标记来维护它……(雾
然后我们就开始非常开心的敲。敲完之后发现,de不出来啊……
这里有以下和正确性相关的细节。
1.merge的时候,要先进行pushdown。我们一般的写法,是只要遇到有一个空树就进行返回。但是这道题中因为要维护最大子段和,需要用左右的来归并,而如果其中有一棵是空树,就会导致另一个没有pushdown,从而影响答案的正确性。
2.在区间翻转的时候要注意。我们需要先翻转自己的左右儿子,之后在标记下放的时候,对左右儿子旋转左右儿子。
3.注意一点就是,对于一个区间的从左/右开始的连续最大子段和,我们必须在它的左/右儿子存在的时候才可以进行更新。一个重要原因是这题有负数,就会导致你把负的答案改成0,使得出错。
4.这个题因为插入和删除很多,所以要进行垃圾回收。回收之后再拿出来的时候,我们需要进行重置,清空所有原来的数据,否则一旦与原来有关联就不知道会发生啥了。
之后还是有好多细节的……基本上都是对于最大子段和的更新过程,确实是比较繁琐的,需要时刻判断一下是否有左右儿子存在来进行计算。
看一下代码。
// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')
#define I inline
using namespace std;
typedef long long ll;
const int M = 1000005;
I int read()
{
int ans = 0,op = 1;char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') op = -1;ch = getchar();}
while(ch >= '0' && ch <= '9') ans = ans * 10 + ch - '0',ch = getchar();
return ans * op;
}
struct tree
{
int lc,rc,size,sum,val,mx,lx,rx,opv,rk;
bool opt,rev;
}t[M<<1];
int bin[M<<3],bintop,n,m,tot,sta[M<<1],top;
char s[20];
I int newnode(int x)
{
int g = bintop ? bin[bintop--] : ++tot;
t[g].size = 1,t[g].sum = t[g].val = t[g].mx = x;
t[g].opv = t[g].lc = t[g].rc = 0;
t[g].opt = t[g].rev = 0;
t[g].rx = t[g].lx = max(0,x),t[g].rk = rand();
return g;
}
I void pushup(int x)
{
t[x].size = t[t[x].lc].size + t[t[x].rc].size + 1;
t[x].sum = t[t[x].lc].sum + t[t[x].rc].sum + t[x].val;
t[x].mx = max(t[x].val,t[t[x].lc].rx + t[t[x].rc].lx + t[x].val);
if(t[x].lc) t[x].mx = max(t[x].mx,t[t[x].lc].mx);
if(t[x].rc) t[x].mx = max(t[x].mx,t[t[x].rc].mx);
t[x].lx = max(t[t[x].lc].lx,t[t[x].lc].sum + t[x].val + t[t[x].rc].lx);
t[x].rx = max(t[t[x].rc].rx,t[t[x].rc].sum + t[x].val + t[t[x].lc].rx);
}
I void rever(int x) {swap(t[x].lx,t[x].rx),swap(t[x].lc,t[x].rc),t[x].rev ^= 1;}
I void cover(int x,int v)
{
t[x].val = v,t[x].sum = t[x].size * v;
t[x].lx = t[x].rx = max(t[x].sum,0);
t[x].mx = max(t[x].sum,t[x].val),t[x].opv = v,t[x].opt = 1;
}
I void pushdown(int x)
{
if(t[x].rev)
{
if(t[x].lc) rever(t[x].lc);
if(t[x].rc) rever(t[x].rc);
t[x].rev ^= 1;
}
if(t[x].opt)
{
if(t[x].lc) cover(t[x].lc,t[x].opv);
if(t[x].rc) cover(t[x].rc,t[x].opv);
t[x].opt = 0,t[x].opv = 0;
}
}
int build(int l,int r,int *a)
{
if(l > r) return 0;
int mid = (l+r) >> 1;
int g = newnode(a[mid]);
t[g].lc = build(l,mid-1,a),t[g].rc = build(mid+1,r,a);
pushup(g);
return g;
}
int merge(int x,int y)
{
pushdown(x),pushdown(y);
if(!x || !y) return x | y;
if(t[x].rk < t[y].rk) {t[x].rc = merge(t[x].rc,y),pushup(x);return x;}
else {t[y].lc = merge(x,t[y].lc),pushup(y);return y;}
}
void splits(int u,int k,int &x,int &y)
{
if(!u) x = y = 0;
else
{
pushdown(u);
if(t[t[u].lc].size >= k) y = u,splits(t[u].lc,k,x,t[u].lc);
else x = u,splits(t[u].rc,k - t[t[u].lc].size - 1,t[u].rc,y);
pushup(u);
}
}
void restore(int x)
{
if(!x) return;
bin[++bintop] = x,restore(t[x].lc),restore(t[x].rc);
}
int a[M<<2],root,pos,num,x,y,z;
int main()
{
srand(time(NULL));
n = read(),m = read();
rep(i,1,n) a[i] = read();
root = build(1,n,a);
while(m--)
{
scanf("%s",s);
if(s[0] == 'G')
{
pos = read(),num = read();
if(num == 0) {printf("0\n");continue;}
splits(root,pos-1,x,y),splits(y,num,z,y);
printf("%d\n",t[z].sum);
root = merge(x,merge(z,y));
}
if(s[0] == 'I')
{
pos = read(),num = read();
if(num == 0) continue;
rep(i,1,num) a[i] = read();
int nroot = build(1,num,a);
splits(root,pos,x,y),root = merge(merge(x,nroot),y);
}
if(s[0] == 'D')
{
pos = read(),num = read();
if(num == 0) continue;
splits(root,pos-1,x,y),splits(y,num,z,y);
root = merge(x,y),restore(z);
}
if(s[0] == 'M' && s[2] == 'K')
{
pos = read(),num = read();
int v = read();
if(num == 0) continue;
splits(root,pos-1,x,y),splits(y,num,z,y);
cover(z,v),root = merge(x,merge(z,y));
}
if(s[0] == 'M' && s[2] == 'X') printf("%d\n",t[root].mx);
if(s[0] == 'R')
{
pos = read(),num = read();
if(num == 0) continue;
splits(root,pos-1,x,y),splits(y,num,z,y);
rever(z),root = merge(x,merge(z,y));
}
}
return 0;
}
当你意识到,每个上一秒都成为永恒。