博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
bzoj 3267: KC采花&&3272&&3638&&3502 线段树
阅读量:5039 次
发布时间:2019-06-12

本文共 2534 字,大约阅读时间需要 8 分钟。

题目大意

给定一个长为n的序列,维护两种操作:

1.单点修改
2.在[l,r]这段区间中取k个互不相交的子段,使子段之和最大.
\(n \leq 50000,k \leq 20\)

题解

四倍经验.(但我的写法太丑过不了3502)

我们可以很简单地构建出一个最大费用最大流模型
把每个点拆点,然后S,T分别连接即可
但是这道题n达到50000,直接上费用流绝对T的不要不要的
我们想一下这样费用流的时候都在干什么
每次找出一个费用最大的区间...把答案加上费用之和...把所有的费用取反...
我们发现我们可以用线段树维护这个过程!
支持最大子段和查询和反转操作
所以我们维护一个最大子段和和最小子段和即可!!
啥?好像好要维护取到最大子段和和最小子段和时的端点?
啥?要维护从左端点的开始的最大子段和和从右端点开始的最大子段和?
好麻烦啊。。。估计是我写丑了...所以3502才被卡空间了...

Code

#include 
#include
#include
using namespace std;typedef long long ll;inline void read(int &x){ x=0;char ch;bool flag = false; while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true; while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;}inline int cat_max(const int &a,const int &b){return a>b ? a:b;}inline int cat_min(const int &a,const int &b){return a
> 1; build(rt<<1,l,mid);build(rt<<1|1,mid+1,r); T[rt] = T[rt<<1] + T[rt<<1|1];}void modify(int rt,int l,int r,int pos,int val){ if(l == r){ T[rt].set(val,l); return; } int mid = l+r >> 1; pushdown(rt,l,r); if(pos <= mid) modify(rt<<1,l,mid,pos,val); else modify(rt<<1|1,mid+1,r,pos,val); T[rt] = T[rt<<1] + T[rt<<1|1];}Node query(int rt,int l,int r,int L,int R){ if(L <= l && r <= R) return T[rt]; int mid = l+r >> 1; pushdown(rt,l,r); if(R <= mid) return query(rt<<1,l,mid,L,R); if(L > mid) return query(rt<<1|1,mid+1,r,L,R); return query(rt<<1,l,mid,L,R) + query(rt<<1|1,mid+1,r,L,R);}void rever(int rt,int l,int r,int L,int R){ if(L <= l && r <= R){T[rt].reve();return;} int mid = l+r >> 1; pushdown(rt,l,r); if(L <= mid) rever(rt<<1,l,mid,L,R); if(R > mid) rever(rt<<1|1,mid+1,r,L,R); T[rt] = T[rt<<1] + T[rt<<1|1];}struct seg{ int l,r; seg(int l=0,int r=0){this->l=l;this->r=r;}}sta[22];int top,n;inline int spfa(int l,int r,int num){ top = 0;int ret = 0; while(num--){ Node x = query(1,1,n,l,r); if(x.mx < 0) break; sta[++top] = seg(x.lx,x.rx); ret += x.mx; rever(1,1,n,x.lx,x.rx); } while(top){ rever(1,1,n,sta[top].l,sta[top].r); --top; } return ret;}int main(){ read(n); for(int i=1;i<=n;++i) read(a[i]); build(1,1,n); int m;read(m); int op,l,r,k; while(m--){ read(op);read(l);read(r); if(op == 0){ modify(1,1,n,l,r); }else{ read(k); printf("%d\n",spfa(l,r,k)); } } getchar();getchar(); return 0;}

转载于:https://www.cnblogs.com/Skyminer/p/6414073.html

你可能感兴趣的文章
java中Hashtable和HashMap的区别(转)
查看>>
关闭数据库
查看>>
webStrom智能提示忽略首字母大小写问题
查看>>
层叠加的五条叠加法则(一)
查看>>
设计模式六大原则(5):迪米特法则
查看>>
对Feature的操作插入添加删除
查看>>
javascript String
查看>>
ecshop 系统信息在哪个页面
查看>>
【转】码云source tree 提交超过100m 为什么大文件推不上去
查看>>
Oracle数据库的增、删、改、查
查看>>
阿里市值超越亚马逊 马云开启下半场技术理想
查看>>
MySql执行分析
查看>>
git使用中的问题
查看>>
yaml文件 .yml
查看>>
linux字符集修改
查看>>
phpcms 添加自定义表单 留言
查看>>
mysql 优化
查看>>
读书笔记 ~ Nmap渗透测试指南
查看>>
WCF 配置文件
查看>>
动态调用WCF服务
查看>>