●CodeForces 280D k-Maximum Subsequence Sum

题链:

http://codeforces.com/problemset/problem/280/D

题解:

神题,巨恶心。
(把原来的那个dp题升级为:序列带修 + 多次询问区间[l,r]内取不超过k段的不重叠子串,使得其和最大)。
按费用流的思路来看,建图方法如下:

每个点拆成两个点 i , i' ,建立超源 S和超汇 T
i -> i' : (1,a[i])
S -> i  : (1,0)
i'-> T  : (1,0)
i'-> i+1: (1,0)
那么对于某段区间,按照spfa最长路费用流去一条路一条路增广,
直到某个时候增广数==k或者增广路的费用为负数就停止。

分析其增广方式,不难发现一个重要特点(可以自己简单伪证一下哈):
每次找到增广路都是连续的一段,即对应着序列区间上和最大的连续的一段。
接下来增广操作,就会取出这一段的权值和,并把这一段的所有数全部 * -1。(就是增广后的反向边的花费)

所以就用线段树维护区间最大子段和以及最小子段和,
并且要支持单点修改和区间 * -1操作。
每次就取出[l,r]区间内的最大的子段,并把对应的子段全部 * -1,
如果取得次数==k或者最大的子段和为负数就停止。

。。。这个线段树不是一般的烦。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXN 100005
#define INF 0x3f3f3f3f
using namespace std;
int a[MAXN];
struct data{
	int sval,lval,rval,sum,sl,sr,lr,rl;
	void init(bool type){
		if(type) lval=rval=sval=-INF;
		else lval=rval=sval=+INF;	
	}
	void reverse(){
		sval*=-1; lval*=-1; rval*=-1; sum*=-1;
	}
	void update(const data &l,const data &r,bool type){
		sum=l.sum+r.sum;
		if(type) 
			lval=max(l.lval,l.sum+r.lval), rval=max(r.rval,r.sum+l.rval),
			sval=max(max(l.sval,r.sval),l.rval+r.lval);
		else 
			lval=min(l.lval,l.sum+r.lval), rval=min(r.rval,r.sum+l.rval),
			sval=min(min(l.sval,r.sval),l.rval+r.lval);
			
		if(l.lval==lval) lr=l.lr; else lr=r.lr;
		
		if(r.rval==rval) rl=r.rl; else rl=l.rl;
		
		if(l.sval==sval) sl=l.sl,sr=l.sr;
		else if(r.sval==sval) sl=r.sl,sr=r.sr;
		else sl=l.rl,sr=r.lr;
	}
};
struct info{
	data maxi,mini;
	void init(){
		maxi.init(1);
		mini.init(0);
	}
};
struct SGT{
	#define ls lson[u]
	#define rs rson[u]
	bool lazy[MAXN<<1];
	int lson[MAXN<<1],rson[MAXN<<1],rt,sz;
	info node[MAXN<<1];
	void init(){
		rt=sz=0;
		memset(lazy,0,sizeof(lazy));
		memset(lson,0,sizeof(lson));
		memset(rson,0,sizeof(rson));
		for(int i=0;i<(MAXN<<1);i++) 
			node[i].init();
	}
	void pushup(info &now,const info &l,const info &r){
		now.maxi.update(l.maxi,r.maxi,1);//___________________维护最大连续和_1__
		now.mini.update(l.mini,r.mini,0);//___________________维护最小连续和_0__
	}
	void pushdown(int u){
		node[ls].maxi.reverse(); node[ls].mini.reverse();
		node[rs].maxi.reverse(); node[rs].mini.reverse();
		swap(node[ls].maxi,node[ls].mini);
		swap(node[rs].maxi,node[rs].mini);
		lazy[u]^=1; lazy[ls]^=1; lazy[rs]^=1;
	}
	void build(int &u,int l,int r){
		u=++sz;
		if(l==r) {
			node[u].maxi=(data){a[l],a[l],a[l],a[l],l,r,r,l};
			node[u].mini=(data){a[l],a[l],a[l],a[l],l,r,r,l};
			return;
		}
		int mid=(l+r)>>1;
		build(ls,l,mid);
		build(rs,mid+1,r);
		pushup(node[u],node[ls],node[rs]);
	}
	void modify(int u,int l,int r,int p){
		if(l==r){
			node[u].maxi=(data){a[l],a[l],a[l],a[l],l,r,r,l};
			node[u].mini=(data){a[l],a[l],a[l],a[l],l,r,r,l};
			return;
		}
		if(lazy[u]) pushdown(u);
		int mid=(l+r)>>1;
		if(p<=mid) modify(ls,l,mid,p);
		else modify(rs,mid+1,r,p);
		pushup(node[u],node[ls],node[rs]);
	}
	void modify(int u,int l,int r,int al,int ar){
		if(al<=l&&r<=ar){
			node[u].maxi.reverse(); node[u].mini.reverse();
			swap(node[u].maxi,node[u].mini);
			lazy[u]^=1; return;
		}
		if(lazy[u]) pushdown(u);
		int mid=(l+r)>>1;
		if(al<=mid) modify(ls,l,mid,al,ar);
		if(mid<ar)  modify(rs,mid+1,r,al,ar);
		pushup(node[u],node[ls],node[rs]);
	}
	info query(int u,int l,int r,int al,int ar){
		if(al<=l&&r<=ar) return node[u];
		info now,lnode,rnode; 
		now.init(); lnode.init(); rnode.init();
		if(lazy[u]) pushdown(u);
		int mid=(l+r)>>1;
		if(al<=mid) lnode=query(ls,l,mid,al,ar);
		if(mid<ar)  rnode=query(rs,mid+1,r,al,ar);
		
		if(mid<al) now=rnode;
		else if(ar<=mid) now=lnode;
		else pushup(now,lnode,rnode);
		return now;
	}
	#undef ls
	#undef rs
}T1;
int N,M,ans;
void dfs(int k,int l,int r){
	info now=T1.query(T1.rt,1,N,l,r);
	if(now.maxi.sval<=0) return;
	ans+=now.maxi.sval;
	T1.modify(T1.rt,1,N,now.maxi.sl,now.maxi.sr);
	if(k-1)dfs(k-1,l,r);
	T1.modify(T1.rt,1,N,now.maxi.sl,now.maxi.sr);
}
int main()
{
	//freopen("280D.in","r",stdin);
	scanf("%d",&N); T1.init();
	for(int i=1;i<=N;i++) scanf("%d",&a[i]);
	T1.build(T1.rt,1,N);
	scanf("%d",&M);
	for(int i=1,c,l,r,k;i<=M;i++){
		scanf("%d",&c);
		if(!c){
			scanf("%d",&k); scanf("%d",&a[k]);
			T1.modify(T1.rt,1,N,k);
		}
		else{
			scanf("%d%d%d",&l,&r,&k);
			ans=0;
			dfs(k,l,r);
			printf("%d\n",ans);
		}
	}
	return 0;
}

posted @ 2017-11-30 20:02  *ZJ  阅读(313)  评论(0编辑  收藏  举报