CF280D k-Maximum Subsequence Sum

CF280D k-Maximum Subsequence Sum

WC现在正在讲网络流,我也来写一题网络流!

一开始真想不到这题能费用流。但是 \(k\) 规模较小告诉我们可以先从一个一个区间贪心做入手。但是纯贪心一定是不对的,所以可以考虑反悔贪心(我觉得这题反悔贪心思路可能还要更简单一点?)。从费用流角度可以更好地描述反悔贪心的思路。

连边 \(i \rightarrow i + 1\),流了这条边就表示选 \(i\) 这个点,然后最大费用最大流就是答案。

直接上线段树模拟找增广路,需要维护单点修改,区间乘 \(-1\),区间最大子段和。

这就比较复杂了,建议想明白再写,正负需要分别维护,还要维护最大字段和的端点,我一个节点维护了 16 个值。

写了好长。

#include <cstdio>
#include <iostream>

#define int long long

using std::swap;

namespace IO {
  #define isdigit(x) (x >= '0' && x <= '9')
  template<typename T>
  inline void read(T &x) {
    x = 0; char ch = getchar(); int f = 0;
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
    for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
    if(f) x = -x;
  }
  template<typename T>
  inline void write(T x) {
    if(x < 0) putchar('-'), x = -x;
    if(x > 9) write(x / 10);
    putchar(x % 10 + '0');
  }
  #undef isdigit
}
using namespace IO;

const int N = 1e5 + 10;
const int inf = 1e15;
int n, a[N];

struct Msg { 
  int val1, lmx1, rmx1, lp1, rp1, pre1, suf1, val2, lmx2, rmx2, lp2, rp2, pre2, suf2, sum;
  inline Msg operator + (const Msg y) const{
    Msg res{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    res.sum = sum + y.sum;
    
    if(lmx1 > sum + y.lmx1) {
      res.pre1 = pre1;
      res.lmx1 = lmx1;
    } else {
      res.pre1 = y.pre1;
      res.lmx1 = sum + y.lmx1;
    }

    if(y.rmx1 > y.sum + rmx1) {
      res.suf1 = y.suf1;
      res.rmx1 = y.rmx1;
    } else {
      res.suf1 = suf1;
      res.rmx1 = y.sum + rmx1;
    }

    res.lp1 = suf1, res.rp1 = y.pre1;
    res.val1 = rmx1 + y.lmx1;
    if(res.val1 < val1) 
      res.val1 = val1, res.lp1 = lp1, res.rp1 = rp1;
    if(res.val1 < y.val1)
      res.val1 = y.val1, res.lp1 = y.lp1, res.rp1 = y.rp1;


    if(lmx2 > -sum + y.lmx2) {
      res.pre2 = pre2;
      res.lmx2 = lmx2;
    } else {
      res.pre2 = y.pre2;
      res.lmx2 = -sum + y.lmx2;
    }

    if(y.rmx2 > -y.sum + rmx2) {
      res.suf2 = y.suf2;
      res.rmx2 = y.rmx2;
    } else {
      res.suf2 = suf2;
      res.rmx2 = -y.sum + rmx2;
    }

    res.lp2 = suf2, res.rp2 = y.pre2;
    res.val2 = rmx2 + y.lmx2;
    if(res.val2 < val2) 
      res.val2 = val2, res.lp2 = lp2, res.rp2 = rp2;
    if(res.val2 < y.val2)
      res.val2 = y.val2, res.lp2 = y.lp2, res.rp2 = y.rp2;
    return res;
  }
}msg[N << 2];

struct Tag {
  int tp;
  inline void apply(Msg &t) const{
    if(tp) {
      t.sum = -t.sum;
      swap(t.lmx1, t.lmx2), swap(t.rmx1, t.rmx2);
      swap(t.pre1, t.pre2), swap(t.suf1, t.suf2);
      swap(t.lp1, t.lp2), swap(t.rp1, t.rp2);
      swap(t.val1, t.val2);
    }
  }
}tag[N << 2];

struct tri{
  int a, b, c;
  inline bool operator < (const tri y) {
    return a < y.a;
  }
};

inline tri max(tri x, tri y) {return y < x ? x : y;}

struct SegTree {
  #define lc (k << 1)
  #define rc (k << 1 | 1)
  #define mid ((l + r) >> 1)

  inline void pushdown(int k) {
    tag[k].apply(msg[lc]), tag[k].apply(msg[rc]);
    tag[lc].tp ^= tag[k].tp, tag[rc].tp ^= tag[k].tp;
    tag[k].tp = 0;
  }

  inline void build(int k, int l, int r) {
    if(l == r) {
      tag[k] = (Tag){0};
      if(a[l] < 0) tag[k] = (Tag){1}, a[l] = -a[l];
      msg[k] = Msg{a[l], a[l], a[l], l, l, l, l, 0, 0, 0, l, l - 1, l - 1, l + 1, a[l]};
      tag[k].apply(msg[k]);
      return;
    }
    build(lc, l, mid), build(rc, mid + 1, r);
    msg[k] = msg[lc] + msg[rc];
  }

  inline void modify(int k, int l, int r, int pos, int v) {
    if(l > pos || r < pos) return;
    if(l == r) {
      tag[k].tp = 0;
      if(v < 0) tag[k] = (Tag){1}, v = -v;
      msg[k] = Msg{v, v, v, l, l, l, l, 0, 0, 0, l, l - 1, l - 1, l + 1, v};
      tag[k].apply(msg[k]);
      return;
    }
    pushdown(k);
    modify(lc, l, mid, pos, v), modify(rc, mid + 1, r, pos, v);
    msg[k] = msg[lc] + msg[rc];
  }

  inline void mul(int k, int l, int r, int L, int R) {
    if(r < L || R < l) return;
    if(L <= l && r <= R) {
      Tag tmp{1};
      tmp.apply(msg[k]);
      tag[k].tp ^= -1;
      return;
    }
    pushdown(k);
    mul(lc, l, mid, L, R);
    mul(rc, mid + 1, r, L, R);
    msg[k] = msg[lc] + msg[rc];
  }

  inline Msg query(int k, int l, int r, int L, int R) {
    if(r < L || R < l) return Msg{-inf, -inf, -inf, 0, 0, 0, 0, -inf, -inf, -inf, 0, 0, 0, 0, 0};
    if(L <= l && r <= R) return msg[k];
    pushdown(k);
    return query(lc, l, mid, L, R) + query(rc, mid + 1, r, L, R);
  }
}seg;

Msg stk[N];
int top;

signed main() {
  read(n);
  for(int i = 1; i <= n; ++i)
    read(a[i]);
  seg.build(1, 1, n);
  int m = 0; read(m);
  for(int i = 1, tp, x, y, z; i <= m; ++i) {
    read(tp);
    if(!tp) {
      read(x), read(y);
      seg.modify(1, 1, n, x, y);
    }
    else {
      read(x), read(y), read(z);
      int sum = 0;
      while(z--) {
        Msg res = seg.query(1, 1, n, x, y);
        stk[++top] = res;
        sum += res.val1;
        seg.mul(1, 1, n, res.lp1, res.rp1);
      }
      printf("%lld\n",sum);
      while(top) seg.mul(1, 1, n, stk[top].lp1, stk[top].rp1), --top;
    }
  }
  return 0;
}
posted @ 2023-01-14 14:15  DCH233  阅读(29)  评论(0编辑  收藏  举报