题目描述

给一列数,要求支持操作: 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 ≤ n, 1 ≤ 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(nk\log 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\n" , ans);
while(tot) update(sta[tot].l , sta[tot].r , 1 , n , 1) , tot -- ;
}
else modify(x , y , 1 , n , 1);
}
return 0;
}

【bzoj3638】Cf172 k-Maximum Subsequence Sum 模拟费用流+线段树区间合并的更多相关文章

  1. BZOJ.3638.CF172 k-Maximum Subsequence Sum(模拟费用流 线段树)

    题目链接 各种zz错误..简直了 /* 19604kb 36292ms 题意:选$k$段不相交的区间,使其权值和最大. 朴素线段树:线段树上每个点维护O(k)个信息,区间合并时O(k^2),总O(mk ...

  2. Codeforces 280D k-Maximum Subsequence Sum [模拟费用流,线段树]

    洛谷 Codeforces bzoj1,bzoj2 这可真是一道n倍经验题呢-- 思路 我首先想到了DP,然后矩阵,然后线段树,然后T飞-- 搜了题解之后发现是模拟费用流. 直接维护选k个子段时的最优 ...

  3. BZOJ 3836 Codeforces 280D k-Maximum Subsequence Sum (模拟费用流、线段树)

    题目链接 (BZOJ) https://www.lydsy.com/JudgeOnline/problem.php?id=3836 (Codeforces) http://codeforces.com ...

  4. BZOJ3638[Codeforces280D]k-Maximum Subsequence Sum&BZOJ3272Zgg吃东西&BZOJ3267KC采花——模拟费用流+线段树

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

  5. CF280D-k-Maximum Subsequence Sum【模拟费用流,线段树】

    正题 题目链接:https://www.luogu.com.cn/problem/CF280D 题目大意 一个长度为\(n\)的序列,\(m\)次操作 修改一个数 询问一个区间中选出\(k\)段不交子 ...

  6. BZOJ2040[2009国家集训队]拯救Protoss的故乡——模拟费用流+线段树+树链剖分

    题目描述 在星历2012年,星灵英雄Zeratul预测到他所在的Aiur行星在M天后会发生持续性暴雨灾害,尤其是他们的首都.而Zeratul作为星灵族的英雄,当然是要尽自己最大的努力帮助星灵族渡过这场 ...

  7. 【BZOJ3638】Cf172 k-Maximum Subsequence Sum 线段树区间合并(模拟费用流)

    [BZOJ3638]Cf172 k-Maximum Subsequence Sum Description 给一列数,要求支持操作: 1.修改某个数的值 2.读入l,r,k,询问在[l,r]内选不相交 ...

  8. HDU5107---K-short Problem (线段树区间 合并、第k大)

    题意:二维平面上 N 个高度为 Hi 建筑物,M次询问,每次询问输出 位于坐标(x ,y)左下角(也就是xi <= x && yi <= y)的建筑物中的第k高的建筑物的高 ...

  9. BZOJ 4276 [ONTAK2015]Bajtman i Okrągły Robin 费用流+线段树优化建图

    Description 有n个强盗,其中第i个强盗会在[a[i],a[i]+1],[a[i]+1,a[i]+2],...,[b[i]-1,b[i]]这么多段长度为1时间中选出一个时间进行抢劫,并计划抢 ...

随机推荐

  1. 搭建大众点评CAT监控平台

    CAT(Central Application Tracking)是基于Java开发的实时应用监控平台,包括实时应用监控,业务监控.关于CAT的具体介绍可移步到CAT官网进行查阅. 1. 环境清单 C ...

  2. 修改SecureCRT默认会话字符集

    修改SecureCRT默认会话字符集 1.找到SecureCRT配置文件 Default.ini 2.修改Default修改为UTF-8 将S:"Output Transformer Nam ...

  3. 【例题收藏】◇例题·III◇ 木と整数 / Integers on a Tree

    ◇例题·III◇ 木と整数 / Integers on a Tree 只需要一个美妙的转换,这道题就会变得无比美妙…… 来源:+AtCoder 2148(ARC-063 E)+ ◆ 题目大意 给定一棵 ...

  4. 文本处理工具-AWK

    awk简介 awk功能与sed相似,都是用来进行文本处理的.awk可以自动地搜索输入文件,并把每一个输入行切分成字段.许多工作都是自动完成的,例如读取每个输入行.字段分割. awk工作原理 awk一次 ...

  5. IDEA怎么生成UML类图

    说之前先说一下Diagram这个单词,意思是图表; 示意图; 图解; [数] 线图的意思. 打开设置 File->Setting或windows下按Ctrl+Alt+S 在搜索框中输入Diagr ...

  6. thinkphp 跳转外网代码(php通用)

    thinkphp 提供了一个重定向但是在跳转外部网站的时候就会比较麻烦 下面一种方法还不错, < ?php //重定向浏览器 header("Location: http://www. ...

  7. 深入理解PHP7之zval

    PHP7已经发布, 如承诺, 我也要开始这个系列的文章的编写, 今天我想先和大家聊聊zval的变化. 在讲zval变化的之前我们先来看看zval在PHP5下面是什么样子 PHP5zval回顾在PHP5 ...

  8. yii rbac

    一.简介 什么是rbac ? rbac是就是基于角色的访问控制. yii提供一套基础的底层接口,我们知道,rbac经历好几个阶段,从rbac0到rbac3,从基础的用户.角色.权限,到动态的rbac处 ...

  9. Linux YUM (Yellowdog Updater, Modified) Commands for Package Management

    Linux YUM (Yellowdog Updater, Modified) Commands for Package Management In this article, we will lea ...

  10. Smail 中的一些点

    smali中所有操作都需要经过寄存器, 本地寄存器以v开头, 参数寄存器以p开头, 非static方法中p0是this 没有-object后缀的操作指令表示操作的对象是基本类型 invoke-dire ...