SMOJ 2201 D (线段树)

来源:互联网 发布:淘宝购物积分怎么用 编辑:程序博客网 时间:2024/05/29 15:07

题目描述

这是一道数据结构题。
我们拥有一个长度为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 1e9using 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;}

这里写图片描述

之所以我不敢涉足
是因为回头亦是绝路

原创粉丝点击