P2042 [NOI2005]维护数列

(10 mins to read)

大毒瘤题区间插入,区间删除,区间覆盖,区间翻转,区间和,区间最大子段和

只说一下splay的话,区间插入和删除怎么做插入:先把插入的所有节点按照中序遍历建成一棵平衡树,然后把l转到根,l+1转到l的儿子,那么直接把这颗平衡树的根作为l+1的左儿子即可删除:同样的,把l-1转到根,r+1转到l-1的儿子,然后直接把r的左儿子变成0即可。这道题操作比较多,需要考虑空间回收。很简单,只要把这课丢掉的树遍历一下每个节点的编号塞到一个数组中,然后每次新开节点的时候,如果数组中有编号就直接取一个,否则再新开节点,不过复用节点要注意信息的清空。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#include <bits/stdc++.h>
using namespace std;
const int N = 5e6 + 5, inf = 1e9;
int n, m, a[N], id[N];
int buc[N], tp;
int rt, tot;
int newnode() { return (tp ? buc[tp--] : ++tot); }
int ch[N][2], sz[N], val[N], sum[N], mx[N], lx[N], rx[N], fa[N];
bool same[N], rev[N];
bool rs(int x) { return ch[fa[x]][1]==x; }
void up(int p)
{
if(!p) return;
int l = ch[p][0], r = ch[p][1];
sum[p] = sum[l] + sum[r] + val[p];
sz[p] = sz[l] + sz[r] + 1;
mx[p] = max({mx[l], mx[r], rx[l]+lx[r]+val[p]});
lx[p] = max(lx[l], sum[l]+val[p]+lx[r]);
rx[p] = max(rx[r], sum[r]+val[p]+rx[l]);
}
void setv(int p, int v)
{
if(!p) return;
val[p] = v, sum[p] = v*sz[p];
lx[p] = rx[p] = (sum[p]>0 ? sum[p] : 0);
mx[p] = (sum[p]>0 ? sum[p] : val[p]);
}
void setrev(int p)
{
if(!p) return;
swap(ch[p][0], ch[p][1]);
swap(lx[p], rx[p]);
}
void down(int p)
{
int l = ch[p][0], r = ch[p][1];
if(same[p])
{
same[l] = 1, setv(l, val[p]);
same[r] = 1, setv(r, val[p]);
same[p] = 0;
}
if(rev[p])
{
rev[l] ^= 1, setrev(l);
rev[r] ^= 1, setrev(r);
rev[p] = 0;
}
}
void rotate(int x)
{
int y = fa[x], z = fa[y], k = rs(x), w = ch[x][k^1];
ch[y][k] = w; fa[w] = y;
ch[z][rs(y)] = x; fa[x] = z;
ch[x][k^1] = y; fa[y] = x;
up(y); up(x);
}
void splay(int x, int g=0)
{
while(fa[x]!=g)
{
int y = fa[x], z = fa[y];
if(z!=g) (rs(x)==rs(y) ? rotate(y) : rotate(x));
rotate(x);
}
if(!g) rt = x;
}
int kth(int p, int k)
{
down(p);
if(ch[p][0]&&sz[ch[p][0]]>=k) return kth(ch[p][0], k);
else if(sz[ch[p][0]]+1==k) return p;
else return kth(ch[p][1], k-sz[ch[p][0]]-1);
}
int split(int l, int r)
{
int x = kth(rt, l-1), y = kth(rt, r+1);
splay(x); splay(y, x);
return ch[y][0];
}
void makesame(int l, int r, int v)
{
int x = split(l, r), y = fa[x];
setv(x, v), same[x] = 1;
up(y); up(fa[y]);
}
void reverse(int l, int r)
{
int x = split(l, r), y = fa[x];
setrev(x), rev[x] ^= 1;
up(y); up(fa[y]);
}
void rec(int x)
{
if(!x) return;
int l = ch[x][0], r = ch[x][1];
rec(l); rec(r);
buc[++tp] = x;
fa[x] = ch[x][0] = ch[x][1] = 0, rev[x] = same[x] = 0;
sz[x] = val[x] = sum[x] = mx[x] = lx[x] = rx[x] = 0;
}
void del(int l, int r)
{
int x = split(l, r), y = fa[x];
rec(ch[y][0]); ch[y][0] = 0;
up(y); up(fa[y]);
}
void bld(int l, int r, int f)
{
if(l>r) return;
int mid = (l+r)>>1, p = id[mid];
val[p] = a[mid];
if(f) fa[p] = id[f], ch[id[f]][mid>f] = p;
if(l==r)
{
mx[p] = sum[p] = a[l];
same[p] = rev[p] = 0;
lx[p] = rx[p] = max(a[l], 0);
sz[p] = 1;
ch[p][0] = ch[p][1] = 0;
}
bld(l, mid-1, mid);
bld(mid+1, r, mid);
up(p);
}
void ins(int l, int r)
{
for(int i=1; i<=r-l+1; i++)
{
scanf("%d", &a[i]);
id[i] = newnode();
}
bld(1, r-l+1, 0);
int x = kth(rt, l), y = kth(rt, l+1);
splay(x); splay(y, x);
int z = id[(r-l+2)>>1];
fa[z] = y, ch[y][0] = z;
up(y); up(x);
}
int main()
{
scanf("%d%d", &n, &m);
mx[0] = -inf, a[1] = -inf, a[n+2] = inf;
for(int i=1; i<=n; i++) scanf("%d", &a[i+1]);
for(int i=1; i<=n+2; i++) id[i] = newnode();
bld(1, n+2, 0);
rt = (n+3)>>1;
while(m--)
{
static char com[10];
scanf("%s", com);
int l, r;
if(com[0]!='M'||com[2]!='X') scanf("%d%d", &l, &r);
++l, r = l + r - 1;
if(com[0]=='I') ins(l, r);
if(com[0]=='D') del(l, r);
if(com[0]=='M')
{
if(com[2]=='X') printf("%d\n", mx[split(2, sz[rt]-1)]);
else
{
int v; scanf("%d", &v);
makesame(l, r, v);
}
}
if(com[0]=='R') reverse(l, r);
if(com[0]=='G') printf("%d\n", sum[split(l, r)]);
}
return 0;
}