[bzoj3638]k-Maximum Subsequence Sum
2016-03-21 21:52
507 查看
题目大意
给定一个序列,需要兹瓷两个操作:1、修改一个元素的值
2、询问一个区间内选取不超过k个(不同询问的k不同但不会超过20)互不相交的子段和的最大值。
想想网络流
我们可以这样建图把i拆成i和i’,然后i->i’一条容量为1(代表最多选一次)费用为ai的边。i’->i+1一条容量为1费用为0的边。s->i容量为1费用为0,i->t容量为1费用为0。那么我们现在就是要求总流量不超过k的最大费用流。做法是每一次找最长增广路,如果权值和小于0直接退出,否则加进答案并将沿途经过的所有边取反。
每一次最多增广1的流量,因此限定最多做k轮即可。
线段树维护
上面的网络流方法有很好的启发作用,我们并不需要真的跑网络流,而是直接模拟其算法过程,每一轮:1:找到最大子段和,如果小于0就退出
2:加入答案,并将该段元素全部取相反数
因此我们只需要打一个能够维护区间最大(或小)(左或右或无)子段和的值(或左右端点)以及区间和。
为什么要维护最小值?因为区间取反后原来的最小值的相反数变成了取反后的最大值。
然后就上吧!
#include<cstdio> #include<algorithm> #define fo(i,a,b) for(i=a;i<=b;i++) using namespace std; const int maxn=100000+10; struct suan{ int l,r,s; friend suan operator +(suan a,suan b){ suan c; c.l=a.l;c.r=b.r; c.s=a.s+b.s; return c; } friend bool operator <(suan a,suan b){ return a.s<b.s; } }; struct dong{ suan smax,lmax,rmax,smin,lmin,rmin,all; bool rev; }; dong merge(dong a,dong b){ dong c; c.smax=max(a.smax,b.smax); c.smax=max(c.smax,a.rmax+b.lmax); c.smin=min(a.smin,b.smin); c.smin=min(c.smin,a.rmin+b.lmin); c.lmax=max(a.lmax,a.all+b.lmax); c.lmin=min(a.lmin,a.all+b.lmin); c.rmax=max(b.rmax,a.rmax+b.all); c.rmin=min(b.rmin,a.rmin+b.all); c.all=a.all+b.all; c.rev=0; return c; } dong tree[maxn*5],sta[100],zlt; int i,j,k,l,r,t,n,m,ans,top; dong newnode(int x,int y){ dong c; c.rev=0; c.smax.s=c.smin.s=c.lmax.s=c.lmin.s=c.rmax.s=c.rmin.s=c.all.s=y; c.smax.l=c.smin.l=c.lmax.l=c.lmin.l=c.rmax.l=c.rmin.l=c.all.l=x; c.smax.r=c.smin.r=c.lmax.r=c.lmin.r=c.rmax.r=c.rmin.r=c.all.r=x; return c; } void mark(int p){ tree[p].rev^=1; swap(tree[p].smax,tree[p].smin); swap(tree[p].lmax,tree[p].lmin); swap(tree[p].rmax,tree[p].rmin); tree[p].smax.s*=-1; tree[p].smin.s*=-1; tree[p].lmax.s*=-1; tree[p].lmin.s*=-1; tree[p].rmax.s*=-1; tree[p].rmin.s*=-1; tree[p].all.s*=-1; } void down(int p,int l,int r){ int mid=(l+r)/2; if (tree[p].rev){ mark(p*2); mark(p*2+1); tree[p].rev=0; } } void change(int p,int l,int r,int a,int b){ if (l==r){ tree[p]=newnode(l,b); return; } down(p,l,r); int mid=(l+r)/2; if (a<=mid) change(p*2,l,mid,a,b);else change(p*2+1,mid+1,r,a,b); tree[p]=merge(tree[p*2],tree[p*2+1]); } void reverse(int p,int l,int r,int a,int b){ if (l==a&&r==b){ mark(p); return; } down(p,l,r); int mid=(l+r)/2; if (b<=mid) reverse(p*2,l,mid,a,b); else if (a>mid) reverse(p*2+1,mid+1,r,a,b); else reverse(p*2,l,mid,a,mid),reverse(p*2+1,mid+1,r,mid+1,b); tree[p]=merge(tree[p*2],tree[p*2+1]); } dong query(int p,int l,int r,int a,int b){ if (l==a&&r==b) return tree[p]; down(p,l,r); int mid=(l+r)/2; if (b<=mid) return query(p*2,l,mid,a,b); else if (a>mid) return query(p*2+1,mid+1,r,a,b); else return merge(query(p*2,l,mid,a,mid),query(p*2+1,mid+1,r,mid+1,b)); } int main(){ scanf("%d",&n); fo(i,1,n){ scanf("%d",&t); change(1,1,n,i,t); } scanf("%d",&m); while (m--){ scanf("%d",&t); if (!t){ scanf("%d%d",&j,&k); change(1,1,n,j,k); } else{ scanf("%d%d%d",&l,&r,&k); ans=top=0; while (k--){ zlt=query(1,1,n,l,r); if (zlt.smax.s<0) break; ans+=zlt.smax.s; sta[++top]=zlt; reverse(1,1,n,zlt.smax.l,zlt.smax.r); } printf("%d\n",ans); while (top){ reverse(1,1,n,sta[top].smax.l,sta[top].smax.r); top--; } } } }
相关文章推荐
- Qemu&KVM第三篇之使用Ubuntu-vm-builder 创建虚拟机
- NSOprationQueue 与 GCD 的区别与选用
- Installtion ID : UUID 统计安装
- apue- chapter 3 文件IO
- ACM程序设计选修课——1058: Lucky Sequence(思考)
- iOS工具种之16进制颜色转为UIColor
- MFC中关于UINT与USHORT
- UI进阶——XMPP即时通讯
- CROC 2016 - Elimination Round (Rated Unofficial Edition) E. Intellectual Inquiry 贪心 构造 dp
- Farey Sequence(欧拉函数)
- INSTALL_FAILED_UID_CHANGED解决办法
- 带大文件飞---威刚UE700-128G优盘速度测试
- 为什么Arduino UNO工作电压是5V,但是需要9V的电源适配器
- CF645E-Intellectual Inquiry 贪心
- iOS开发UI篇—ios应用数据存储方式(归档) :转发
- iOS UIImageView居中
- UITableView,UICollectionView和CoreData完美结合进行增删改操作,如何导入大量数据,如何利用NSEntityMigrationPol
- Selected collating sequence not supported by the operating system vc6.0报错
- Core Data Model Versioning and Data Migration Programming Guide
- Android开发优化之——对界面UI的优化(1)