题目描述
这是一道数据结构题。
我们拥有一个长度为n的数组a[i]。
我们有m次操作。操作有两种类型:
0 i val:表示我们要把a[i]修改为val;
1 l r k:表示我们要求出区间[l,r]的最多k个不相交子区间,并使得各个子区间的数的和尽量大,需要注意的是,我们也可以不选择区间,这时候数的和为0.
N,m不超过10^5.
所有的ai和val的绝对值均不超过500.k不超过20.询问的数目不超过10000.
所有输入保证合法。
输入格式
第一行为数据组数。
对于每一组数据:
第一行为正整数n。
第二行n个整数表示ai。
第三行一个正整数m。
接下来m行每行一个操作。具体看题面。
输出格式
对于每一组数据:
对于每一组询问,一行一个整数表示答案。
输入样例
1
9
9 -8 9 -1 -1 -1 9 -8 9
3
1 1 9 1
1 1 9 2
1 4 6 3
输出样例
17
25
0
Solution
线段树好题 + 码农级数据结构题!
比赛时想着如何将dp改成数据结构(明显是线段树),结果没想出来。后来才知道具体做法很简单。每次在区间中找一段最大的,并将这个区间取反,就是变成它的相反数。然后每个询问直接做k次就行了。
至于为什么想一下就知道了。假如这次贪心地取影响了后面的,那么后面取到它的相反数,就去除了影响。这样就保证贪心没有“后效性”了。这点我觉得有点像网络流里的反向边。很神奇哦。
虽说想法是naive的,但写法是要命的。这题我写了一个晚上写完了,第二天调了半个下午无果,丢下去打球,打完球回到机房后灵光一现,改了一下函数实现方式就立马过了!(得出结论:我太菜鸡了QAQ。。)
这题的基础模型是动态修改+求区间连续最大和。这是很经典的线段树模型,维护的东西有Lmax, Rmax, Tmax,sum等,比较多。这题由于要取反,还要记最大区间的左右端点,同样还要借助于左连续一段和右连续一段。于是还要记Lmaxp, Rmaxp, Tmaxp1, Tmaxp2,还有翻转标记rev。对于取反,我是开了两棵线段树,取反就Swap。总之要维护的东西很多,查询要用到的也不少,代码将近200行左右。比起LCT什么的,不算太长。但一直码不对,就有可能心态爆炸。
需要注意的是,每次询问后记得取反回来之类的细节。
Code
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#define MAXN 100010
#define Max(a, b) ((a) > (b)) ? (a) : (b)
#define INF 1e9
using namespace std;
int nG;
int n, m;
int a[MAXN];
struct Tnode{
int Lmax, Rmax, Tmax;
int sum, Lmaxp, Rmaxp, Tmaxp1, Tmaxp2;
bool rev;
Tnode() {}
Tnode(int _a, int _b, int _c, int _d, int _e, int _f, int _g, int _h, bool _i){
Lmax = _a;
Rmax = _b;
Tmax = _c;
sum = _d;
Lmaxp = _e;
Rmaxp = _f;
Tmaxp1 = _g;
Tmaxp2 = _h;
rev = _i;
}
}tree[2][MAXN<<2];
void Swap(Tnode& A, Tnode& B){
Tnode C = A; A = B; B = C;
}
void Up(Tnode& root, Tnode& Lson, Tnode& Rson){
root.sum = Lson.sum + Rson.sum;
if(Lson.Lmax > Lson.sum + Rson.Lmax){
root.Lmax = Lson.Lmax;
root.Lmaxp = Lson.Lmaxp;
}
else{
root.Lmax = Lson.sum + Rson.Lmax;
root.Lmaxp = Rson.Lmaxp;
}
if(Rson.Rmax > Rson.sum + Lson.Rmax){
root.Rmax = Rson.Rmax;
root.Rmaxp = Rson.Rmaxp;
}
else{
root.Rmax = Rson.sum + Lson.Rmax;
root.Rmaxp = Lson.Rmaxp;
}
if(Lson.Tmax >= Rson.Tmax && Lson.Tmax >= Lson.Rmax + Rson.Lmax){
root.Tmax = Lson.Tmax;
root.Tmaxp1 = Lson.Tmaxp1;
root.Tmaxp2 = Lson.Tmaxp2;
}
else if(Rson.Tmax >= Lson.Tmax && Rson.Tmax >= Lson.Rmax + Rson.Lmax){
root.Tmax = Rson.Tmax;
root.Tmaxp1 = Rson.Tmaxp1;
root.Tmaxp2 = Rson.Tmaxp2;
}
else{
root.Tmax = Lson.Rmax + Rson.Lmax;
root.Tmaxp1 = Lson.Rmaxp;
root.Tmaxp2 = Rson.Lmaxp;
}
root.rev = false;
}
void Down(int root, int Lson, int Rson){
if(!tree[0][root].rev) return;
Swap(tree[0][Lson], tree[1][Lson]);
tree[0][Lson].rev ^= 1;
tree[1][Lson].rev ^= 1;
Swap(tree[0][Rson], tree[1][Rson]);
tree[0][Rson].rev ^= 1;
tree[1][Rson].rev ^= 1;
}
void build(int root, int L, int R){
if(L == R){
for(int i = 0; i < 2; i++){
if(!i) tree[i][root].Tmax = tree[i][root].Rmax = tree[i][root].Lmax = tree[i][root].sum = a[L];
else tree[i][root].Tmax = tree[i][root].Rmax = tree[i][root].Lmax = tree[i][root].sum = -a[L];
tree[i][root].Tmaxp1 = tree[i][root].Tmaxp2 = tree[i][root].Lmaxp = tree[i][root].Rmaxp = L;
tree[i][root].rev = false;
}
return;
}
int mid = (L + R) >> 1, Lson = root << 1, Rson = root << 1 | 1;
build(Lson, L, mid);
build(Rson, mid+1, R);
Up(tree[0][root], tree[0][Lson], tree[0][Rson]);
Up(tree[1][root], tree[1][Lson], tree[1][Rson]);
}
void update(int root, int L, int R, int x, int v){
if(x > R || x < L) return;
if(L == x && x == R){
tree[0][root].sum = v;
tree[1][root].sum = -v;
tree[0][root].Tmax = tree[0][root].Rmax = tree[0][root].Lmax = v;
tree[1][root].Tmax = tree[1][root].Rmax = tree[1][root].Lmax = -v;
return;
}
int mid = (L + R) >> 1, Lson = root << 1, Rson = root << 1 | 1;
Down(root, Lson, Rson);
update(Lson, L, mid, x, v);
update(Rson, mid+1, R, x, v);
Up(tree[0][root], tree[0][Lson], tree[0][Rson]);
Up(tree[1][root], tree[1][Lson], tree[1][Rson]);
}
void flip(int root, int L, int R, int x, int y){
if(x > R || y < L) return;
if(x <= L && y >= R){
Swap(tree[0][root], tree[1][root]);
tree[0][root].rev ^= 1;
tree[1][root].rev ^= 1;
return;
}
int mid = (L + R) >> 1, Lson = root << 1, Rson = root << 1 | 1;
Down(root, Lson, Rson);
flip(Lson, L, mid, x, y);
flip(Rson, mid+1, R, x, y);
Up(tree[0][root], tree[0][Lson], tree[0][Rson]);
Up(tree[1][root], tree[1][Lson], tree[1][Rson]);
}
Tnode query(int root, int L, int R, int x, int y){
if(x <= L && y >= R) return tree[0][root];
int mid = (L + R) >> 1, Lson = root << 1, Rson = root << 1 | 1;
Down(root, Lson, Rson);
tree[0][root].rev = tree[1][root].rev = false;
if(y <= mid) return query(Lson, L, mid, x, y);
else if(x > mid) return query(Rson, mid+1, R, x, y);
else{
Tnode temp;
Tnode temp1 = query(Lson, L, mid, x, y);
Tnode temp2 = query(Rson, mid+1, R, x, y);
Up(temp, temp1, temp2);
return temp;
}
}
int main(){
freopen("2201.in", "r", stdin);
freopen("2201.out", "w", stdout);
scanf("%d", &nG);
while(nG --){
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
build(1, 1, n);
scanf("%d", &m);
int a, b, c, d;
for(int i = 1; i <= m; i++){
scanf("%d%d%d", &a, &b, &c);
if(!a) update(1, 1, n, b, c);
else{
scanf("%d", &d);
int ans = 0;
Tnode here[25];
for(int k = 1; k <= d; k++){
here[k] = query(1, 1, n, b, c);
if(here[k].Tmax > 0){
ans += here[k].Tmax;
flip(1, 1, n, here[k].Tmaxp1, here[k].Tmaxp2);
}
}
for(int k = 1; k <= d; k++)
if(here[k].Tmax > 0) flip(1, 1, n, here[k].Tmaxp1, here[k].Tmaxp2);
printf("%d\n", ans);
}
}
}
return 0;
}
之所以我不敢涉足
是因为回头亦是绝路