CF280D k-Maximum Subsequence Sum (线段树)

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/z286830682/article/details/19018929

10W个数10W个操作,操作有两种:

修改单点的值;

从区间[L,R]中选出最多k段不相交区间,使和最大。

k最大为20

用dp思路时间复杂度O(mk^2lgn) == TLE。so,会有其他方法。

如果用费用流解决k段区间最大和,那么找增广路的过程是怎么样的呢。

step 1,找到一条费用最大的增广路L

step 2,若找不到增广路,或L已经是负费用了,goto step 4,否则计算新费用,

step 3,删除L,在残量图中加入与L方向相反,费用相反的反向弧,goto step 1

step 4,输出答案

上面的过程每一轮都至少使流量+1,最多持续k轮。看起来比dp的k^2系数要好,但是要是每次都建图费用流必须TLE,所以可以简化成这样:

step 1,找到[L,R]中的一段最大连续和[l,r]

step 2,若sum[l,r]>0,将sum[l,r]计入答案,否则goto step 4

step 3,将[l,r]的所有数字取反,goto step 1

step 4,输出答案

这个就可以用线段树来实现了,时间复杂度O(mklgn),常数略大。

岛娘和clj出的题真是不能玩啊,哪怕知道算法敲出来也累死了- -b,我再也不要玩线段树了。。

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
using namespace std;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
const int N = 101000;
struct Line {
        int l,r,s;
        Line(int l=0,int r=0,int s=0):l(l),r(r),s(s) {}
        Line operator + (Line tt) {
                return Line(l,tt.r,s+tt.s);
        }
        bool operator < (const Line &tt) const {
                return s<tt.s;
        }
        void show() { printf("::%d %d %d\n",l,r,s); }
};
struct Node {
        Line Lmax,Lmin,Rmax,Rmin,Vmax,Vmin,V;
        int rev;
        Node(int l=0,int r=0,int s=0) {
                Lmax = Lmin = Rmax = Rmin = Vmax = Vmin = V = Line(l,r,s);
                rev = 0;
        }
        void up(Node a,Node b) {
                if (a.Lmax.l==0) { *this = b; return; }
                Lmax = max(a.Lmax,a.V+b.Lmax);
                Lmin = min(a.Lmin,a.V+b.Lmin);
                Rmax = max(a.Rmax+b.V,b.Rmax);
                Rmin = min(a.Rmin+b.V,b.Rmin);
                Vmax = max(a.Rmax,b.Lmax);
                Vmax = max(Vmax,max(a.Vmax,b.Vmax));
                Vmax = max(Vmax,a.Rmax+b.Lmax);
                Vmax = max(Vmax,max(Lmax,Rmax));
                Vmin = min(a.Rmin,b.Lmin);
                Vmin = min(Vmin,min(a.Vmin,b.Vmin));
                Vmin = min(Vmin,a.Rmin+b.Lmin);
                Vmin = min(Vmin,min(Lmin,Rmin));
                V = a.V+b.V;
        }
};
Node tree[N<<2];
int n,m;
void rev(int rt) {
        Node &x = tree[rt];
        x.rev ^= 1;
        swap(x.Lmin,x.Lmax); swap(x.Rmin,x.Rmax); swap(x.Vmin,x.Vmax);
        x.Lmin.s *= -1; x.Lmax.s *= -1; x.Rmin.s *= -1; x.Rmax.s *= -1; 
        x.Vmin.s *= -1; x.Vmax.s *= -1; x.V.s *= -1;
}
void down(int rt) {
        if (tree[rt].rev) {
                rev(rt<<1); 
                rev(rt<<1|1);
                tree[rt].rev = 0;
        }
}
void build(int l,int r,int rt) {
        if (l==r) {
                int val; scanf("%d",&val);
                tree[rt] = Node(l,r,val);
                return ;
        }
        int mid = l+r>>1;
        build(lson);
        build(rson);
        tree[rt].up(tree[rt<<1],tree[rt<<1|1]);
}
void modify(int p,int v,int l,int r,int rt) {
        if (l==r) {
                tree[rt] = Node(l,r,v); return ;
        }
        int mid = l+r>>1;
        down(rt);
        if (p<=mid) modify(p,v,lson); 
        else modify(p,v,rson);
        tree[rt].up(tree[rt<<1],tree[rt<<1|1]);
}
void rev(int L,int R,int l,int r,int rt) {
        if (L<=l && r<=R) {
                rev(rt); return ;
        }
        int mid = l+r>>1;
        down(rt);
        if (L<=mid) rev(L,R,lson);
        if (mid< R) rev(L,R,rson);
        tree[rt].up(tree[rt<<1],tree[rt<<1|1]);
}
Node query(int L,int R,int l,int r,int rt) {
        if (L<=l && r<=R) return tree[rt];
        int mid = l+r>>1;
        down(rt);
        Node ret;
        if (L<=mid) ret.up(ret,query(L,R,lson));
        if (R> mid) ret.up(ret,query(L,R,rson));
        return ret;
}
int main() {
        scanf("%d",&n);
        build(1,n,1);
        scanf("%d",&m);
        while (m--) {
                int op;
                scanf("%d",&op);
                if (op==0) {
                        int p,v;
                        scanf("%d%d",&p,&v);
                        modify(p,v,1,n,1);
                } else {
                        int l,r,k,ans = 0;
                        scanf("%d%d%d",&l,&r,&k);
                        vector<Line> zxc;
                        for (int i = 0; i < k; i ++) {
                                Line t = query(l,r,1,n,1).Vmax;
                                zxc.push_back(t);
                                rev(t.l,t.r,1,n,1);
                                if (t.s>0) ans += t.s;
                                else break;
                        }
                        for (int i = 0; i < (int)zxc.size(); i ++)
                                rev(zxc[i].l,zxc[i].r,1,n,1);
                        printf("%d\n",ans);
                }
        }
        return 0;
}


展开阅读全文

没有更多推荐了,返回首页