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; }
CF280D k-Maximum Subsequence Sum (线段树)
原文:http://blog.csdn.net/hei_nero/article/details/19018929