【BZOJ3502】【PA2012】Tanie linie

【题目链接】

【五倍经验链接】

【思路要点】

  • 容易发现一种可行的费用流建边。
  • 用线段树模拟上述费用流,我们需要实现查找区间最大子段和和区间取反。
  • 时间复杂度 O(MLogN) O ( M L o g N )

【代码】


#include<bits/stdc++.h>

using namespace std;

#define MAXN  200005

template <typename T> void read(T &x) {
  x = 0; int f = 1;
  char c = getchar();
  for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
  for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
  x *= f;
}
struct Segment_Tree {
  struct info {
      int lmax, rmax, smax;
      int lmin, rmin, smin;
      int lmaxpos, lminpos;
      int rmaxpos, rminpos;
      int smaxl, sminl;
      int smaxr, sminr;
      int sum;
  };
  info merge(info a, info b) {
      info ans;
      ans.sum = a.sum + b.sum;
      /*lmax lmaxpos*/
      if (a.lmax > a.sum + b.lmax) {
          ans.lmax = a.lmax;
          ans.lmaxpos = a.lmaxpos;
      } else {
          ans.lmax = a.sum + b.lmax;
          ans.lmaxpos = b.lmaxpos;
      }
      /*rmax rmaxpos*/
      if (b.rmax > b.sum + a.rmax) {
          ans.rmax = b.rmax;
          ans.rmaxpos = b.rmaxpos;
      } else {
          ans.rmax = b.sum + a.rmax;
          ans.rmaxpos = a.rmaxpos;
      }
      /*lmin lminpos*/
      if (a.lmin < a.sum + b.lmin) {
          ans.lmin = a.lmin;
          ans.lminpos = a.lminpos;
      } else {
          ans.lmin = a.sum + b.lmin;
          ans.lminpos = b.lminpos;
      }
      /*rmin rminpos*/
      if (b.rmin < b.sum + a.rmin) {
          ans.rmin = b.rmin;
          ans.rminpos = b.rminpos;
      } else {
          ans.rmin = b.sum + a.rmin;
          ans.rminpos = a.rminpos;
      }
      /*smax smaxl smaxr*/
      if (a.smax > b.smax) {
          ans.smax = a.smax;
          ans.smaxl = a.smaxl;
          ans.smaxr = a.smaxr;
      } else {
          ans.smax = b.smax;
          ans.smaxl = b.smaxl;
          ans.smaxr = b.smaxr;
      }
      if (a.rmax + b.lmax > ans.smax) {
          ans.smax = a.rmax + b.lmax;
          ans.smaxl = a.rmaxpos;
          ans.smaxr = b.lmaxpos;
      }
      /*smin sminl sminr*/
      if (a.smin < b.smin) {
          ans.smin = a.smin;
          ans.sminl = a.sminl;
          ans.sminr = a.sminr;
      } else {
          ans.smin = b.smin;
          ans.sminl = b.sminl;
          ans.sminr = b.sminr;
      }
      if (a.rmin + b.lmin < ans.smin) {
          ans.smin = a.rmin + b.lmin;
          ans.sminl = a.rminpos;
          ans.sminr = b.lminpos;
      }
      return ans;
  }
  void reverse(info &a) {
      a.sum = -a.sum;
      swap(a.lmax, a.lmin);
      a.lmax = -a.lmax;
      a.lmin = -a.lmin;
      swap(a.rmax, a.rmin);
      a.rmax = -a.rmax;
      a.rmin = -a.rmin;
      swap(a.smax, a.smin);
      a.smax = -a.smax;
      a.smin = -a.smin;
      swap(a.lmaxpos, a.lminpos);
      swap(a.rmaxpos, a.rminpos);
      swap(a.smaxl, a.sminl);
      swap(a.smaxr, a.sminr);
  }
  info new_node(int value, int pos) {
      info ans;
      ans.sum = value;
      ans.lmax = ans.rmax = ans.smax = value;
      ans.lmin = ans.rmin = ans.smin = value;
      ans.lmaxpos = ans.lminpos = pos;
      ans.rmaxpos = ans.rminpos = pos;
      ans.smaxl = ans.sminl = pos;
      ans.smaxr = ans.sminr = pos;
      return ans;
  }
  struct Node {
      int lc, rc;
      bool tag;
      info value;
  } a[MAXN];
  int root, size, n;
  void pushdown(int root) {
      if (a[root].tag) {
          int tmp;
          tmp = a[root].lc;
          a[tmp].tag ^= true;
          reverse(a[tmp].value);
          tmp = a[root].rc;
          a[tmp].tag ^= true;
          reverse(a[tmp].value);
          a[root].tag = false;
      }
  }
  void update(int root) {
      a[root].value = merge(a[a[root].lc].value, a[a[root].rc].value);
  }
  void build(int root, int l, int r, int *value) {
      if (l == r) {
          a[root].value = new_node(value[l], l);
          return;
      }
      int mid = (l + r) / 2;
      a[root].lc = ++size;
      build(size, l, mid, value);
      a[root].rc = ++size;
      build(size, mid + 1, r, value);
      update(root);
  }
  void init(int x, int *value) {
      n = x;
      root = size = 0;
      build(root, 1, n, value);
  }
  void reverse(int root, int l, int r, int ql, int qr) {
      if (l == ql && r == qr) {
          reverse(a[root].value);
          a[root].tag ^= true;
          return;
      }
      pushdown(root);
      int mid = (l + r) / 2;
      if (mid >= ql) reverse(a[root].lc, l, mid, ql, min(mid, qr));
      if (mid + 1 <= qr) reverse(a[root].rc, mid + 1, r, max(mid + 1, ql), qr);
      update(root);
  }
  int query(int k) {
      int ans = 0;
      for (int i = 1; i <= k; i++) {
          info tmp = a[root].value;
          if (tmp.smax > 0) {
              reverse(root, 1, n, tmp.smaxl, tmp.smaxr);
              ans += tmp.smax;
          } else return ans;
      }
      return ans;
  }
} SMT;
int value[MAXN];
int main() {
  int n, k; read(n), read(k);
  for (int i = 1; i <= n; i++)
      read(value[i]);
  SMT.init(n, value);
  cout << SMT.query(k) << endl;
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值