这道算是一道合格的Splay基础题。距离上一次那道简单的Splay时间比较长,因为经历了元旦晚会和之后的一个小假期没写题。
这道题涵盖的Splay的操作还是比较多的,适合练手。写的时候思路一定要清晰,否则不好调。
推荐自顶向下写。我就是先写的最大的框架,判断输入,调用哪个函数。写出大框架之后就轮到挨个写函数了,这些函数也是有上下关系的,最靠上的当然就是最直接的对应每个操作的函数。我使用分裂和合并操作来完成它们。这样很简单地写完了这些函数。之后就该写其下一层的分裂和合并,其中涉及到splay,pushdown和maintain,思路清晰,很快写好。之后写下一层的splay,这个函数写得很简短,就用到了rotate。再最后,就应该写最底层的pushdown,maintain,rotate和find。一气呵成,写完代码大概用了1个小时多一点。
然而,调试的过程有一点坎坷(被COGS坑了一下,本地怎么跑都没事,COGS上就是全T,完全没有输出,加了内存池优化空间后在BZOJ上是过了)。细节较多的是mx的维护,在maintain中需要注意一下。还有就是maintain的调用的时间,以及调用时要保证合法性(比如偷懒的我在maintain里没有判断lc和rc是否为0就直接拿它们更新rt,那么就要保证lc或rc是0的时候的su,ml,mr,mx不会影响到rt)。
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
void get (int &x)
{
char c = getchar(); bool neg = 0; x = 0;
while (c < '0' || c > '9') {if (c == '-') neg = 1; c = getchar();}
while (c <= '9' && c >= '0') x = x*10+c-48, c = getchar();
if (neg) x = -x;
}
void get (char *s)
{
char c = getchar(); int num = 0;
while (c < 'A' || c > 'Z') c = getchar();
while ((c <= 'Z' && c >= 'A') || c == '-') s[num++] = c, c = getchar();
}
void put (int x)
{
if (x == 0) putchar('0');
if (x < 0) {putchar('-'); x = -x;}
char s[15]; int num = 0;
while (x) s[++num] = (x%10)+48, x /= 10;
while (num) putchar(s[num--]);
putchar ('\n');
}
int max (int a, int b, int c, int d, int e)
{
return max(a,max(b,max(c,max(d,e))));
}
queue <int> mem;
struct node
{
int va, lc, rc, fa, sz, ch, re, su, ml, mr, mx;
void set0()
{va=lc=rc=fa=sz=re=su=0, ch=ml=mr=mx=-(1<<20);}
};
struct SplayTree
{
node P[500005]; int root;
//flags : ch re
void pushdown (int rt)
{
int lc = P[rt].lc, rc = P[rt].rc;
if (P[rt].ch >= -1000)
{
int ch = P[rt].ch;
P[lc].ch = P[lc].va = ch;
P[rc].ch = P[rc].va = ch;
P[lc].su = ch*P[lc].sz;
P[rc].su = ch*P[rc].sz;
if (ch <= 0)
P[lc].ml = P[lc].mr = P[lc].mx = ch,
P[rc].ml = P[rc].mr = P[rc].mx = ch;
else P[lc].ml = P[lc].mr = P[lc].mx = P[lc].su;
P[rc].ml = P[rc].mr = P[rc].mx = P[rc].su;
P[rt].ch = -(1<<20);
}
if (P[rt].re)
{
P[lc].re ^= 1, P[rc].re ^= 1;
swap (P[lc].lc, P[lc].rc);
swap (P[lc].ml, P[lc].mr);
swap (P[rc].lc, P[rc].rc);
swap (P[rc].ml, P[rc].mr);
P[rt].re = 0;
}
}
//int va, lc, rc, fa, sz, ch, re, su, ml, mr, mx;
void maintain (int rt)
{
P[0].set0();
int lc = P[rt].lc, rc = P[rt].rc;
P[rt].sz = P[lc].sz + P[rc].sz + 1;
P[rt].su = P[lc].su + P[rc].su + P[rt].va;
P[rt].ml = max (P[lc].ml, P[lc].su+P[rt].va+max(P[rc].ml,0));
P[rt].mr = max (P[rc].mr, P[rc].su+P[rt].va+max(P[lc].mr,0));
P[rt].mx = max (P[rt].ml,P[rt].mr,max(P[lc].mr,0)+P[rt].va+max(P[rc].ml,0),P[lc].mx,P[rc].mx);
}
int makenewtree (int tot)
{
if (!tot) return 0;
int rt = mem.front(), lc, rc, lcsz=tot/2, rcsz=tot-lcsz-1;
mem.pop();
P[rt].sz = tot; P[rt].ch = -(1<<30);
P[rt].lc = makenewtree(lcsz);
P[P[rt].lc].fa = rt;
get(P[rt].va);
P[rt].rc = makenewtree(rcsz);
P[P[rt].rc].fa = rt;
maintain(rt);
return rt;
}
int find (int rt, int k)
{
if (!rt || !k) return 0;
int rk = P[P[rt].lc].sz+1;
pushdown (rt);
if (rk == k) return rt;
if (rk > k) return find (P[rt].lc, k);
if (rk < k) return find (P[rt].rc, k-rk);
}
void reuse (int rt)
{
if (!rt) return ;
mem.push (rt);
reuse (P[rt].lc);
reuse (P[rt].rc);
P[rt].set0();
}
void rotate (int rt)
{
int fa = P[rt].fa, gfa = P[fa].fa;
if (fa == root) root = rt;
pushdown(fa); pushdown(rt);
if (P[fa].lc == rt)
{
P[fa].lc = P[rt].rc, P[P[fa].lc].fa = fa;
P[rt].rc = fa, P[fa].fa = rt;
}
else
{
P[fa].rc = P[rt].lc, P[P[fa].rc].fa = fa;
P[rt].lc = fa, P[fa].fa = rt;
}
if(P[gfa].lc == fa) P[gfa].lc=rt; else P[gfa].rc=rt;
P[rt].fa = gfa;
maintain(fa); maintain(rt);
}
void splay (int rt)
{
while (rt != root)
{
int fa = P[rt].fa, gfa = P[fa].fa;
if (gfa && (P[fa].lc==rt)==(P[gfa].lc==fa)) rotate(fa);
rotate(rt);
}
}
int split (int rt, int op) // 1 left 0 right
{
if (!rt) return 0;
int t;
splay (rt);
pushdown(root);
if(op) t=P[rt].lc, P[rt].lc=P[t].fa=0;
else t=P[rt].rc, P[rt].rc=P[t].fa=0;
maintain(root);
return t;
}
void merge (int L, int R)
{
if (!L) {root=R; return;}
if (!R) {root=L; return;}
root = L;
splay (find(root,P[root].sz));
pushdown(root);
P[root].rc = R, P[R].fa = root;
maintain(root);
}
void insert (int pos, int tot)
{
int rt = makenewtree(tot);
if (!pos) merge (rt, root);
else
{
int op = split (find(root,pos),0);
merge (root, rt);
merge (root, op);
}
}
void erase (int pos, int tot)
{
int op = split (find(root,pos),1);
if (tot+1 <= P[root].sz)
{
reuse(split (find(root,tot+1), 1));
merge (op, root);
}
else
{
reuse (root);
root = op;
}
}
void update (int pos, int tot)
{
int c; get(c);
int op = split (find(root,pos),1);
int op2= split (find(root,tot),0);
P[root].ch = P[root].va = c, P[root].su = c*P[root].sz;
if (c <= 0) P[root].ml = P[root].mr = P[root].mx = c;
else P[root].ml = P[root].mr = P[root].mx = P[root].su;
merge (root,op2);
merge (op, root);
}
void rever (int pos, int tot)
{
int op = split (find(root,pos),1);
int op2= split (find(root,tot),0);
P[root].re ^= 1;
swap(P[root].ml, P[root].mr);
swap(P[root].lc, P[root].rc);
merge (root,op2);
merge (op, root);
}
void getsum (int pos, int tot)
{
if (!tot) {puts("0"); return ;}
int op = split (find(root,pos),1);
int op2= split (find(root,tot),0);
put (P[root].su);
merge (root,op2);
merge (op, root);
}
void maxsum (int pos, int tot)
{
put (P[root].mx);
}
}Solve;
int n, m;
int getcommand()
{
char s[15]; get(s);
if (s[0] == 'I') return 1;
if (s[0] == 'D') return 2;
if (s[0] == 'R') return 4;
if (s[0] == 'G') return 5;
if (s[0] == 'M' && s[2] == 'K') return 3;
return 0;
}
int main()
{
get(n); get(m);
//insert(a,b) insert b numbers behind a
for (int i = 1; i <= 500000; i++) mem.push(i);
Solve.insert(0, n);
while (m--)
{
int cmd = getcommand(), pos, tot;
if (cmd) {get(pos); get(tot);}
if (cmd == 1) Solve.insert(pos, tot);
if (cmd == 2) Solve.erase (pos, tot);
if (cmd == 3) Solve.update(pos, tot);
if (cmd == 4) Solve.rever (pos, tot);
if (cmd == 5) Solve.getsum(pos, tot);
if (cmd == 0) Solve.maxsum(pos, tot);
}
return 0;
}