zoukankan      html  css  js  c++  java
  • ●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
    ",ans);
    		}
    	}
    	return 0;
    }

  • 相关阅读:
    Git 快速入门
    【工具软件】-Win10 应用软件找不到映射网络驱动器的解决方法
    Java笔记(十五)……面向对象IV多态(polymorphism)
    Java笔记(十四)……抽象类与接口
    Java笔记(十三)……面向对象III继承(inheritance)
    Java笔记(十二)……类中各部分加载顺序及存放位置问题
    Java笔记(十一)……单例设计模式
    Java笔记(十)……面向对象II封装(Encapsulation)
    Java笔记(九)……面向对象I
    Java笔记(八)……数组
  • 原文地址:https://www.cnblogs.com/zj75211/p/7931041.html
Copyright © 2011-2022 走看看