您的位置:首页 > 产品设计 > UI/UE

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);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: