CF280D k-Maximum Subsequence Sum

题目链接:洛谷

题目大意:【题意翻译已经够直白了】


首先,相信大家一开始都是想去直接dp,但是发现复杂度不对。

于是我们考虑一个黑科技:模拟费用流(相信大部分人看见数据范围就绝对不会想到费用流)

我们考虑进行拆点,设i->i':(1,a[i]),i'->i+1:(1,0),而且总流量$\leq k$,然后就跑最大费用最大流。

这显然会$T$成sb,不过这个图比较简单,我们可以考虑手玩一下。

然后就发现每次的增广路就是这个区间里的最大和的子段对应的路径,然后再把这个最大和的子段里面所有数取相反数(反向边)。

然后就可以用线段树维护,这个线段树需要以下操作。

1.单点修改

2.对于区间[l,r],先找出这个区间的最大和的子段,然后把这个子段取相反数。

不过码量让人想哭。。。(好不容易调出来,纪念一下。

  1 #include<bits/stdc++.h>
  2 #define Rint register int
  3 using namespace std;
  4 const int N = 100003;
  5 struct Node {
  6     int L, R, sum, maxv, maxl, maxr, minv, minl, minr, lmax, lmaxid, lmin, lminid, rmax, rmaxid, rmin, rminid;
  7     bool rev;
  8     inline Node(int pos = 0, int val = 0){
  9         L = R = maxl = maxr = minl = minr = lmaxid = lminid = rmaxid = rminid = pos;
 10         sum = maxv = minv = lmax = lmin = rmax = rmin = val;
 11         rev = false;
 12     }
 13 } seg[N << 2], q[22];
 14 inline Node merge(const Node &a, const Node &b){
 15     Node now;
 16     now.L = a.L; now.R = b.R;
 17     now.sum = a.sum + b.sum;
 18     if(a.lmax >= a.sum + b.lmax) now.lmax = a.lmax, now.lmaxid = a.lmaxid;
 19     else now.lmax = a.sum + b.lmax, now.lmaxid = b.lmaxid;
 20     if(a.lmin <= a.sum + b.lmin) now.lmin = a.lmin, now.lminid = a.lminid;
 21     else now.lmin = a.sum + b.lmin, now.lminid = b.lminid;
 22     if(b.rmax >= b.sum + a.rmax) now.rmax = b.rmax, now.rmaxid = b.rmaxid;
 23     else now.rmax = b.sum + a.rmax, now.rmaxid = a.rmaxid;
 24     if(b.rmin <= b.sum + a.rmin) now.rmin = b.rmin, now.rminid = b.rminid;
 25     else now.rmin = b.sum + a.rmin, now.rminid = a.rminid;
 26     now.maxv = a.rmax + b.lmax; now.maxl = a.rmaxid; now.maxr = b.lmaxid;
 27     if(now.maxv < a.maxv) now.maxv = a.maxv, now.maxl = a.maxl, now.maxr = a.maxr;
 28     if(now.maxv < b.maxv) now.maxv = b.maxv, now.maxl = b.maxl, now.maxr = b.maxr;
 29     now.minv = a.rmin + b.lmin; now.minl = a.rminid; now.minr = b.lminid;
 30     if(now.minv > a.minv) now.minv = a.minv, now.minl = a.minl, now.minr = a.minr;
 31     if(now.minv > b.minv) now.minv = b.minv, now.minl = b.minl, now.minr = b.minr;
 32     now.rev = false;
 33     return now;
 34 }
 35 inline void pushup(int x){seg[x] = merge(seg[x << 1], seg[x << 1 | 1]);}
 36 inline void rev(Node &a){
 37     a.rev ^= 1;
 38     a.sum = -a.sum;
 39     swap(a.lmax, a.lmin); swap(a.lmaxid, a.lminid);
 40     a.lmax = -a.lmax; a.lmin = -a.lmin;
 41     swap(a.rmax, a.rmin); swap(a.rmaxid, a.rminid);
 42     a.rmax = -a.rmax; a.rmin = -a.rmin;
 43     swap(a.maxv, a.minv); swap(a.maxl, a.minl); swap(a.maxr, a.minr);
 44     a.maxv = -a.maxv; a.minv = -a.minv;
 45 }
 46 inline void pushdown(int x){
 47     if(seg[x].rev){
 48         rev(seg[x << 1]);
 49         rev(seg[x << 1 | 1]);
 50         seg[x].rev = false;
 51     }
 52 }
 53 int n, m, a[N];
 54 inline void build(int x, int L, int R){
 55     if(L == R){
 56         seg[x] = Node(L, a[L]);
 57         return;
 58     }
 59     int mid = L + R >> 1;
 60     build(x << 1, L, mid);
 61     build(x << 1 | 1, mid + 1, R);
 62     pushup(x);
 63 }
 64 inline void change(int x, int L, int R, int pos, int val){
 65     if(L == R){
 66         seg[x] = Node(L, val);
 67         return;
 68     }
 69     int mid = L + R >> 1;
 70     pushdown(x);
 71     if(pos <= mid) change(x << 1, L, mid, pos, val);
 72     else change(x << 1 | 1, mid + 1, R, pos, val);
 73     pushup(x);
 74 }
 75 inline void modify(int x, int L, int R, int l, int r){
 76     if(l <= L && R <= r){
 77         rev(seg[x]);
 78         return;
 79     }
 80     int mid = L + R >> 1;
 81     pushdown(x);
 82     if(l <= mid) modify(x << 1, L, mid, l, r);
 83     if(mid < r) modify(x << 1 | 1, mid + 1, R, l, r);
 84     pushup(x);
 85 }
 86 inline Node query(int x, int L, int R, int l, int r){
 87     if(l <= L && R <= r) return seg[x];
 88     int mid = L + R >> 1;
 89     pushdown(x);
 90     if(r <= mid) return query(x << 1, L, mid, l, r);
 91     else if(mid < l) return query(x << 1 | 1, mid + 1, R, l, r);
 92     else return merge(query(x << 1, L, mid, l, r), query(x << 1 | 1, mid + 1, R, l, r));
 93 }
 94 //inline void dfs(int x, int L, int R){
 95 //    if(L == R){
 96 //        printf("%d ", seg[x].maxv);
 97 //        return;
 98 //    }
 99 //    int mid = L + R >> 1;
100 //    pushdown(x);
101 //    dfs(x << 1, L, mid);
102 //    dfs(x << 1 | 1, mid + 1, R);
103 //}
104 int main(){
105     scanf("%d", &n);
106     for(Rint i = 1;i <= n;i ++) scanf("%d", a + i);
107     build(1, 1, n);
108     scanf("%d", &m);
109     while(m --){
110         int opt, x, y, k;
111         scanf("%d%d%d", &opt, &x, &y);
112         if(opt == 0)
113             change(1, 1, n, x, y);
114         else {
115             scanf("%d", &k);
116             int ans = 0, pos = k;
117             for(Rint i = 1;i <= k;i ++){
118                 q[i] = query(1, 1, n, x, y);
119                 if(q[i].maxv <= 0){pos = i - 1; break;}
120                 modify(1, 1, n, q[i].maxl, q[i].maxr);
121 //                dfs(1, 1, n); puts("");
122                 ans += q[i].maxv;
123             }
124             for(Rint i = 1;i <= pos;i ++) modify(1, 1, n, q[i].maxl, q[i].maxr);
125             printf("%d\n", ans);
126         }
127     }
128 } 
View Code

 

转载于:https://www.cnblogs.com/AThousandMoons/p/10623871.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值