BZOJ 3638 k-Maximum Subsequence Sum
2016-03-24 12:43
246 查看
Description
给一列数,要求支持操作:1.修改某个数的值
2.读入l,r,k,询问在[l,r]内选不相交的不超过k个子段,最大的和是多少。
Solution
怎么做
[b]可以用最大费用最大流做[/b]把一个点i拆成两个点i1,i2,i1向i2连一个容量为1,费用为a[i]的边;然后i2向(i+1)1连一条容量为1,费用为0的边,然后其他的建边很明显。我们每次流完,为了防止再流一遍,把流过的边权取反,很明显要这样。
[b]但是用网络流的做法比暴搜还慢啊[/b]
模拟一下网络流,我们发现,每次的最大费用最大流都是找一个最大和子段,然后再取反,我们可以用数据结构维护。
用什么
这种题目看上去就像一个数据结构维护的题。支持查询,修改,维护和,最大与最小(因为我们取反的时候最大最小要交换)和每一段的左端点和右端点。
线段树明显可以搞定。
怎么维护左右端点
结构体套结构体!!!一个struct套另一个struct,但是要重载运算符,这样的常数会小一点。
Code
常数真的好大!打的不优美……#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define fo(i,a,b) for(i=a;i<=b;i++) using namespace std; const int maxn=100007; int i,j,k,l,n,m,ans,o,tt; int a[maxn]; struct haofana{ int l,r,o; friend haofana operator +(haofana x,haofana y){ haofana z; z.l=min(x.l,y.l);z.r=max(y.r,x.r); z.o=x.o+y.o; return z; } friend bool operator <(haofana x,haofana y){ return x.o<y.o; } }ans1,b[200]; struct node{ haofana lda,lxiao,rda,rxiao,sum,xiao,da; bool lazy; }t[maxn*5]; void merge(node &x,node y,node z){ x.sum=y.sum+z.sum; x.lda=max(y.lda,y.sum+z.lda); x.rda=max(z.rda,z.sum+y.rda); x.lxiao=min(y.lxiao,y.sum+z.lxiao); x.rxiao=min(z.rxiao,z.sum+y.rxiao); x.da=max(y.da,z.da); x.da=max(x.da,y.rda+z.lda); x.xiao=min(y.xiao,z.xiao); x.xiao=min(x.xiao,y.rxiao+z.lxiao); x.lazy=0; } void fan(int x){ t[x].sum.o*=-1; t[x].da.o*=-1; t[x].lda.o*=-1; t[x].rda.o*=-1; t[x].lxiao.o*=-1; t[x].rxiao.o*=-1; t[x].lazy^=1; t[x].xiao.o*=-1; swap(t[x].da,t[x].xiao); swap(t[x].lda,t[x].lxiao); swap(t[x].rda,t[x].rxiao); } void lazydown(int x){ if(t[x].lazy){ fan(x*2); fan(x*2+1); t[x].lazy=0; } } void newdian(node &x,int l,int r,int p){ x.lda.l=x.lxiao.l=x.rda.l=x.rxiao.l=x.sum.l=x.xiao.l=x.da.l=l; x.lda.r=x.lxiao.r=x.rda.r=x.rxiao.r=x.sum.r=x.xiao.r=x.da.r=r; x.lda.o=x.lxiao.o=x.rda.o=x.rxiao.o=x.sum.o=x.xiao.o=x.da.o=p; x.lazy=0; } void build(int x,int l,int r){ if(l==r){ newdian(t[x],l,r,a[l]); } else{ int mid=(l+r)/2; build(x*2,l,mid); build(x*2+1,mid+1,r); merge(t[x],t[x*2],t[x*2+1]); } } void change(int x,int l,int r,int y,int z){ if(l==r){ newdian(t[x],l,r,z); } else{ int mid=(l+r)/2; lazydown(x); if(y<=mid)change(x*2,l,mid,y,z);else change(x*2+1,mid+1,r,y,z); merge(t[x],t[x*2],t[x*2+1]); } } node find(int x,int l,int r,int y,int z){ node q; if(l==y&&r==z){ return t[x]; } else{ lazydown(x); int mid=(l+r)/2; if(z<=mid)return find(x*2,l,mid,y,z);else if (mid<y)return find(x*2+1,mid+1,r,y,z); else{ merge(q,find(x*2,l,mid,y,mid),find(x*2+1,mid+1,r,mid+1,z)); return q; } } } void negatea(int x,int l,int r,int y,int z){ if(l==y&&r==z){ fan(x); } else{ lazydown(x); int mid=(l+r)/2; if(z<=mid)negatea(x*2,l,mid,y,z);else if(mid<y)negatea(x*2+1,mid+1,r,y,z); else{ negatea(x*2,l,mid,y,mid); negatea(x*2+1,mid+1,r,mid+1,z); } merge(t[x],t[x*2],t[x*2+1]); } } int main(){ freopen("0.in","r",stdin); scanf("%d",&n); fo(i,1,n){ scanf("%d",&a[i]); } build(1,1,n); scanf("%d",&m); while(m--){ scanf("%d",&k); ans=0; if(k){ scanf("%d%d%d",&l,&tt,&o); int u=0; while(o--){ ans1=find(1,1,n,l,tt).da; if(ans1.o<0)break; ans+=ans1.o; b[++u]=ans1; negatea(1,1,n,ans1.l,ans1.r); } printf("%d\n",ans); while(u){ negatea(1,1,n,b[u].l,b[u].r); u--; } }else{ scanf("%d%d",&l,&tt); change(1,1,n,l,tt); } } }
相关文章推荐
- Leetcode 128. Longest Consecutive Sequence
- Codeforces-632D Longest Subsequence
- 控件UI性能调优 -- SizeChanged不是万能的
- 酷狗音乐模仿还在继续之UI界面源码下载
- JS高程读书笔记-第一、二章-内附在线思维导图和quizlet卡片
- IOS中UITableViewCell使用详解
- 原生的强大DOM选择器querySelector - querySelector和querySelectorAll
- easyui解析$.parser.parse()的学习,使用地方
- iOS UIStepper 加减计数器
- UIStackView入门示例解析
- UE的注册流程
- easyui checkbox 初始化时设为已选的方法
- java的build
- hdu 5306 Gorgeous Sequence
- 一个无序整数数组中找到最长连续序列(Longest Consecutive Sequence)和两个元素使得相差最小
- UIImagePickerController控件自带按钮显示中文的办法
- pku1947rebuilding roads 树形DP
- cf#VK Cup 2015 - Qualification Round 2-C - Name Quest-贪心
- EasyUI两种动态添加tab Iframe页面的方法
- EasyUI两种动态添加tab Iframe页面的方法