zoukankan      html  css  js  c++  java
  • 【bzoj3638】Cf172 k-Maximum Subsequence Sum 模拟费用流+线段树区间合并

    题目描述

    给一列数,要求支持操作: 1.修改某个数的值 2.读入l,r,k,询问在[l,r]内选不相交的不超过k个子段,最大的和是多少。

    输入

    The first line contains integer n (1 ≤ n ≤ 105), showing how many numbers the sequence has. The next line contains n integers a1, a2, ..., an (|ai| ≤ 500).

    The third line contains integer m (1 ≤ m ≤ 105) — the number of queries. The next m lines contain the queries in the format, given in the statement.

    All changing queries fit into limits: 1 ≤ i ≤ n|val| ≤ 500.

    All queries to count the maximum sum of at most k non-intersecting subsegments fit into limits: 1 ≤ l ≤ r ≤ n1 ≤ k ≤ 20. It is guaranteed that the number of the queries to count the maximum sum of at most k non-intersecting subsegments doesn't exceed 10000.

    输出

    For each query to count the maximum sum of at most k non-intersecting subsegments print the reply — the maximum sum. Print the answers to the queries in the order, in which the queries follow in the input.

    样例输入

    9
    9 -8 9 -1 -1 -1 9 -8 9
    3
    1 1 9 1
    1 1 9 2
    1 4 6 3

    样例输出

    17
    25
    0


    题解

    模拟费用流+线段树区间合并

    一开始想了个类似于dp的线段树区间合并结果一看数据范围果断放弃了。。。看了题解才知道是模拟费用流。。。

    考虑如果用费用流的话怎么处理:每个点有一个大小为点权的费用,每次选择一段区间,获得这些点权和的费用,然后反向边使得它们的费用取相反数。

    这个过程需要维护最大连续子段和(及其位置)、支持区间翻转。可以使用线段树来维护。

    每个节点维护这段区间的区间和,包含左端点的最大连续子段和、包含右端点的最大连续子段和、整体的最大连续子段和,以及最小连续字段和;还要维护翻转标记。同时,对于和及连续字段和还要维护出现的区间位置。

    每个询问不断的找区间内最大连续子段和,如果其大于0则取出并区间取相反数(模拟增广的过程)。最后再把这些取了相反数的区间还原回来。

    代码量极大。。。强烈建议使用结构体重载运算符以减少代码量。

    时间复杂度$O(nklog n)$。

    #include <cstdio>
    #include <algorithm>
    #define N 100010
    #define lson l , mid , x << 1
    #define rson mid + 1 , r , x << 1 | 1
    using namespace std;
    struct data
    {
    	int v , l , r;
    	data() {}
    	data(int V , int L , int R) {v = V , l = L , r = R;}
    	bool operator<(const data &a)const {return v < a.v;}
    	data operator+(const data &a)const {return data(v + a.v , l , a.r);}
    	data operator-()const {return data(-v , l , r);}
    }now , sta[25];
    struct seg
    {
    	data vsum , lmax , lmin , rmax , rmin , tmax , tmin;
    	int rev;
    	seg() {}
    	seg(int v , int p)
    	{
    		vsum = data(v , p , p) , rev = 0;
    		if(v > 0)
    		{
    			lmax = rmax = tmax = data(v , p , p);
    			lmin = data(0 , p , p - 1) , rmin = data(0 , p + 1 , p) , tmin = data(0 , 0 , 0);
    		}
    		else
    		{
    			lmax = data(0 , p , p - 1) , rmax = data(0 , p + 1 , p) , tmax = data(0 , 0 , 0);
    			lmin = rmin = tmin = data(v , p , p);
    		}
    	}
    	seg operator+(const seg &a)const
    	{
    		seg ans;
    		ans.vsum = vsum + a.vsum;
    		ans.lmax = max(lmax , vsum + a.lmax) , ans.lmin = min(lmin , vsum + a.lmin);
    		ans.rmax = max(a.rmax , rmax + a.vsum) , ans.rmin = min(a.rmin , rmin + a.vsum);
    		ans.tmax = max(rmax + a.lmax , max(tmax , a.tmax)) , ans.tmin = min(rmin + a.lmin , min(tmin , a.tmin));
    		ans.rev = 0;
    		return ans;
    	}
    }a[N << 2];
    inline void pushup(int x)
    {
    	a[x] = a[x << 1] + a[x << 1 | 1];
    }
    inline void rever(int x)
    {
    	swap(a[x].lmax , a[x].lmin) , swap(a[x].rmax , a[x].rmin) , swap(a[x].tmax , a[x].tmin);
    	a[x].vsum = -a[x].vsum;
    	a[x].lmax = -a[x].lmax , a[x].lmin = -a[x].lmin;
    	a[x].rmax = -a[x].rmax , a[x].rmin = -a[x].rmin;
    	a[x].tmax = -a[x].tmax , a[x].tmin = -a[x].tmin;
    	a[x].rev ^= 1;
    }
    inline void pushdown(int x)
    {
    	if(a[x].rev) rever(x << 1) , rever(x << 1 | 1) , a[x].rev = 0;
    }
    void build(int l , int r , int x)
    {
    	if(l == r)
    	{
    		int v;
    		scanf("%d" , &v) , a[x] = seg(v , l);
    		return;
    	}
    	int mid = (l + r) >> 1;
    	build(lson) , build(rson);
    	pushup(x);
    }
    void modify(int p , int v , int l , int r , int x)
    {
    	if(l == r)
    	{
    		a[x] = seg(v , l);
    		return;
    	}
    	pushdown(x);
    	int mid = (l + r) >> 1;
    	if(p <= mid) modify(p , v , lson);
    	else modify(p , v , rson);
    	pushup(x);
    }
    void update(int b , int e , int l , int r , int x)
    {
    	if(b <= l && r <= e)
    	{
    		rever(x);
    		return;
    	}
    	pushdown(x);
    	int mid = (l + r) >> 1;
    	if(b <= mid) update(b , e , lson);
    	if(e > mid) update(b , e , rson);
    	pushup(x);
    }
    seg query(int b , int e , int l , int r , int x)
    {
    	if(b <= l && r <= e) return a[x];
    	pushdown(x);
    	int mid = (l + r) >> 1;
    	if(e <= mid) return query(b , e , lson);
    	else if(b > mid) return query(b , e , rson);
    	else return query(b , e , lson) + query(b , e , rson);
    }
    int main()
    {
    	int n , m , opt , x , y , z , tot , ans;
    	scanf("%d" , &n);
    	build(1 , n , 1);
    	scanf("%d" , &m);
    	while(m -- )
    	{
    		scanf("%d%d%d" , &opt , &x , &y);
    		if(opt == 1)
    		{
    			scanf("%d" , &z) , tot = ans = 0;
    			while(tot < z)
    			{
    				now = query(x , y , 1 , n , 1).tmax;
    				if(now.v <= 0) break;
    				ans += now.v , update(now.l , now.r , 1 , n , 1);
    				sta[++tot] = now;
    			}
    			printf("%d
    " , ans);
    			while(tot) update(sta[tot].l , sta[tot].r , 1 , n , 1) , tot -- ;
    		}
    		else modify(x , y , 1 , n , 1);
    	}
    	return 0;
    }
    

     

  • 相关阅读:
    4月13日
    java线程池开启多线程
    cenos 7 zookeeper Error contacting service. It is probably not running
    io.lettuce.core.RedisCommandTimeoutException: Command timed out
    springboot java jar指定启动的jar外部配置文件
    ApplicationContextAware
    YYYYMMdd和yyyyMMdd的区别
    gpg加解密异常
    第四周学习及读书笔记
    第3章 直流电机的工作原理及特性 学习笔记(二)
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7609414.html
Copyright © 2011-2022 走看看