#线段树,模拟费用流#CF280D k-Maximum Subsequence Sum
题目
给定一个大小为 的序列,要求支持单点修改和查询区间内至多 个不交子区间之和的最大值(可以不取)
分析
考虑源点向每个点、每个点向汇点流流量1费用0的边,每个点向右边的点流流量1费用的边,流量最大为 ,这样构建出一个费用流的模型。
很显然,退流相当于给区间取反,而可以利用反悔贪心,在线段树上维护最大子段和和最小子段和,在最大子段和大于0的情况下取反至多 次区间,查询完再恢复原状
复杂度
代码
#include <cstdio>
#include <cctype>
#include <algorithm>
#include <stack>
using namespace std;
const int N=100011; int n,a[N];
stack<pair<int,int> >st;
int iut(){
int ans=0,f=1; char c=getchar();
while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans*f;
}
void print(int ans){
if (ans<0) putchar('-'),ans=-ans;
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
struct Rec{int l,r,z;};
struct rec{
Rec wmax,wmin,lmax,lmin,rmax,rmin; int sum,lazy;
void ptag(int x,int y){
wmax=wmin=lmax=lmin=rmax=rmin=(Rec){x,x,y};
sum=y,lazy=0;
}
void rev(){
swap(wmax,wmin),swap(lmax,lmin),swap(rmax,rmin);
wmax.z=-wmax.z,wmin.z=-wmin.z,
lmax.z=-lmax.z,lmin.z=-lmin.z,
rmax.z=-rmax.z,rmin.z=-rmin.z;
sum=-sum,lazy^=1;
}
}w[N<<2];
rec pup(rec f,rec g){
rec h; h.lazy=0;
h.sum=f.sum+g.sum;
if (f.lmax.z<f.sum+g.lmax.z) h.lmax=(Rec){f.lmax.l,g.lmax.r,f.sum+g.lmax.z};
else h.lmax=f.lmax;
if (f.lmin.z>f.sum+g.lmin.z) h.lmin=(Rec){f.lmin.l,g.lmin.r,f.sum+g.lmin.z};
else h.lmin=f.lmin;
if (g.rmax.z<f.rmax.z+g.sum) h.rmax=(Rec){f.rmax.l,g.rmax.r,f.rmax.z+g.sum};
else h.rmax=g.rmax;
if (g.rmin.z>f.rmin.z+g.sum) h.rmin=(Rec){f.rmin.l,g.rmin.r,f.rmin.z+g.sum};
else h.rmin=g.rmin;
h.wmax=f.wmax.z>g.wmax.z?f.wmax:g.wmax;
if (h.wmax.z<f.rmax.z+g.lmax.z) h.wmax=(Rec){f.rmax.l,g.lmax.r,f.rmax.z+g.lmax.z};
h.wmin=f.wmin.z<g.wmin.z?f.wmin:g.wmin;
if (h.wmin.z>f.rmin.z+g.lmin.z) h.wmin=(Rec){f.rmin.l,g.lmin.r,f.rmin.z+g.lmin.z};
return h;
}
void build(int k,int l,int r){
if (l==r){
w[k].ptag(l,a[l]);
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
w[k]=pup(w[k<<1],w[k<<1|1]);
}
void update(int k,int l,int r,int x,int y){
if (l==r){
w[k].ptag(x,y);
return;
}
int mid=(l+r)>>1;
if (w[k].lazy){
w[k<<1].rev(),w[k<<1|1].rev();
w[k].lazy=0;
}
if (x<=mid) update(k<<1,l,mid,x,y);
else update(k<<1|1,mid+1,r,x,y);
w[k]=pup(w[k<<1],w[k<<1|1]);
}
void flip(int k,int l,int r,int x,int y){
if (l==x&&r==y){
w[k].rev();
return;
}
int mid=(l+r)>>1;
if (w[k].lazy){
w[k<<1].rev(),w[k<<1|1].rev();
w[k].lazy=0;
}
if (y<=mid) flip(k<<1,l,mid,x,y);
else if (x>mid) flip(k<<1|1,mid+1,r,x,y);
else flip(k<<1,l,mid,x,mid),flip(k<<1|1,mid+1,r,mid+1,y);
w[k]=pup(w[k<<1],w[k<<1|1]);
}
rec query(int k,int l,int r,int x,int y){
if (l==x&&r==y) return w[k];
int mid=(l+r)>>1;
if (w[k].lazy){
w[k<<1].rev(),w[k<<1|1].rev();
w[k].lazy=0;
}
if (y<=mid) return query(k<<1,l,mid,x,y);
else if (x>mid) return query(k<<1|1,mid+1,r,x,y);
else return pup(query(k<<1,l,mid,x,mid),query(k<<1|1,mid+1,r,mid+1,y));
}
int main(){
n=iut();
for (int i=1;i<=n;++i) a[i]=iut();
build(1,1,n);
for (int Q=iut();Q;--Q)
if (iut()){
int l=iut(),r=iut(),k=iut(),ans=0;
while (k--){
rec t=query(1,1,n,l,r);
if (t.wmax.z<=0) break;
ans+=t.wmax.z;
flip(1,1,n,t.wmax.l,t.wmax.r);
st.push(make_pair(t.wmax.l,t.wmax.r));
}
print(ans),putchar(10);
while (!st.empty()) flip(1,1,n,st.top().first,st.top().second),st.pop();
}else{
int x=iut(),y=iut();
update(1,1,n,x,y);
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
2021-04-05 #Multi-SG#Poj 3537 Crosses and Crosses
2021-04-05 #Multi-SG#HDU 5795 A Simple Nim
2021-04-05 #Multi-SG#HDU 3032 Nim or not Nim?
2021-04-05 #SG函数#HDU 1848 Fibonacci again and again