普通版
题目大意
~~~~~~ 一个长度为 n n n 的序列 a 1 . . . a n a_1...a_n a1...an,让你从中选出 m m m 个连续段,使得选出来的和最大。
【 O ( n m ) O(nm) O(nm)】
~~~~~~
设
f
i
,
j
f_{i,j}
fi,j 表示前
i
i
i 个数,共选了
j
j
j 个连续段,所得到的最大和。
~~~~~~
设
g
i
,
j
=
max
{
f
1..
i
,
j
}
g_{i,j}=\max\{ f_{1..i, j} \}
gi,j=max{f1..i,j}, 设
S
S
S 表示
a
a
a 的前缀和。
f
i
,
j
=
max
{
S
i
−
S
k
+
g
k
,
j
−
1
}
~~~~~~f_{i,j}=\max\{ S_i-S_k+g_{k,j-1} \}
fi,j=max{Si−Sk+gk,j−1}
~~~~~~
然后搞一下就是
O
(
n
m
)
O(nm)
O(nm) 的了。
【 O ( m l o g n ) O(m~log~n) O(m log n)】
~~~~~~
源点向每一个点
i
i
i 连一条容量为
1
1
1、费用为
a
i
a_i
ai 的边,每个点
i
i
i 向
i
+
1
i+1
i+1 连一条容量为
1
1
1、费用为
a
i
+
1
a_{i+1}
ai+1 的边,每个点向汇点连一条容量为
1
1
1、费用为
0
0
0 的边。
~~~~~~
这样建图,每增广一次,相当于取出了一个连续段,又由于有反向弧这种操作,所以直接增广
m
m
m 次就可以了。(当然,如果增广出来是负数,可以直接退出)
~~~~~~
当然直接跑费用流肯定会 T。
~~~~~~
引入费用流只是为了引入反向弧这种机制。我们发现实际上是每次贪心地选取一个最大子段而已,那么选完之后我们就把这段取反就行了。
~~~~~~
这个用线段树实现,维护的变量挺多的。
加强版
题目大意
~~~~~~
给你一个长度为
n
n
n 的序列
a
1
.
.
.
a
n
a_1...a_n
a1...an,有如下两种操作:
1
x
y
~~~~~~1~x~y
1 x y:将
a
x
a_x
ax 的值改为
y
y
y
2
l
r
k
~~~~~~2~l~r~k
2 l r k:询问区间
[
l
,
r
]
[l, r]
[l,r] 的最大
k
k
k 子段和。
【 O ( m l o g n ) O(m~log~n) O(m log n)】
~~~~~~ 像上面那样,既然都已经打了个线段树了,那就再加个单点修改。
代码
普通
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long LL;
const int maxn=5e4+5;
struct TR{
LL s,sl,sr,st;
int wzi,wzj,wzl,wzr;
};
int n,m;
LL a[maxn];
TR tr[2][4*maxn];
bool bz[4*maxn];
TR merge(TR a,TR b)
{
TR re;
re.s=a.s+b.s;
if (a.st>b.st)
{
re.st=a.st;
re.wzi=a.wzi, re.wzj=a.wzj;
} else
{
re.st=b.st;
re.wzi=b.wzi, re.wzj=b.wzj;
}
if (a.sr+b.sl>re.st)
{
re.st=a.sr+b.sl;
re.wzi=a.wzr, re.wzj=b.wzl;
}
if (a.sl>a.s+b.sl)
{
re.sl=a.sl;
re.wzl=a.wzl;
} else
{
re.sl=a.s+b.sl;
re.wzl=b.wzl;
}
if (b.sr>b.s+a.sr)
{
re.sr=b.sr;
re.wzr=b.wzr;
} else
{
re.sr=b.s+a.sr;
re.wzr=a.wzr;
}
return re;
}
void tr_js(int k,int l,int r)
{
if (l==r)
{
tr[0][k].s=tr[0][k].sl=tr[0][k].sr=tr[0][k].st=a[l];
tr[0][k].wzi=tr[0][k].wzj=tr[0][k].wzl=tr[0][k].wzr=l;
tr[1][k].s=tr[1][k].sl=tr[1][k].sr=tr[1][k].st=-a[l];
tr[1][k].wzi=tr[1][k].wzj=tr[1][k].wzl=tr[1][k].wzr=l;
return;
}
int t=k<<1, t1=(l+r)>>1;
tr_js(t,l,t1), tr_js(t+1,t1+1,r);
tr[0][k]=merge(tr[0][t],tr[0][t+1]);
tr[1][k]=merge(tr[1][t],tr[1][t+1]);
}
void update(int k,int t)
{
if (!bz[k]) return;
swap(tr[0][t],tr[1][t]);
swap(tr[0][t+1],tr[1][t+1]);
bz[t]^=bz[k];
bz[t+1]^=bz[k];
bz[k]=0;
}
void xg_many(int k,int l,int r,int x,int y)
{
if (l==x && r==y)
{
swap(tr[0][k],tr[1][k]);
bz[k]^=1;
return;
}
int t=k<<1, t1=(l+r)>>1;
update(k,t);
if (y<=t1) xg_many(t,l,t1,x,y);
else if (x>t1) xg_many(t+1,t1+1,r,x,y);
else xg_many(t,l,t1,x,t1), xg_many(t+1,t1+1,r,t1+1,y);
tr[0][k]=merge(tr[0][t],tr[0][t+1]);
tr[1][k]=merge(tr[1][t],tr[1][t+1]);
}
LL get(int m)
{
LL re=0;
while (m--)
{
if (tr[0][1].st<0) break;
re+=tr[0][1].st;
xg_many(1,1,n,tr[0][1].wzi,tr[0][1].wzj);
}
return re;
}
int main()
{
scanf("%d %d",&n,&m);
fo(i,1,n) scanf("%lld",&a[i]);
tr_js(1,1,n);
printf("%lld\n",get(m));
}
加强
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=1e5+5;
struct TR{
int s,sl,sr,st,wzi,wzj,wzl,wzr;
};
int n,a[maxn];
TR tr[2][4*maxn];
bool bz[4*maxn];
TR merge(TR a,TR b)
{
TR re;
re.s=a.s+b.s;
if (a.st>b.st)
{
re.st=a.st;
re.wzi=a.wzi, re.wzj=a.wzj;
} else
{
re.st=b.st;
re.wzi=b.wzi, re.wzj=b.wzj;
}
if (a.sr+b.sl>re.st)
{
re.st=a.sr+b.sl;
re.wzi=a.wzr, re.wzj=b.wzl;
}
if (a.sl>a.s+b.sl)
{
re.sl=a.sl;
re.wzl=a.wzl;
} else
{
re.sl=a.s+b.sl;
re.wzl=b.wzl;
}
if (b.sr>b.s+a.sr)
{
re.sr=b.sr;
re.wzr=b.wzr;
} else
{
re.sr=b.s+a.sr;
re.wzr=a.wzr;
}
return re;
}
void tr_js(int k,int l,int r)
{
if (l==r)
{
tr[0][k].s=tr[0][k].sl=tr[0][k].sr=tr[0][k].st=a[l];
tr[0][k].wzi=tr[0][k].wzj=tr[0][k].wzl=tr[0][k].wzr=l;
tr[1][k].s=tr[1][k].sl=tr[1][k].sr=tr[1][k].st=-a[l];
tr[1][k].wzi=tr[1][k].wzj=tr[1][k].wzl=tr[1][k].wzr=l;
return;
}
int t=k<<1, t1=(l+r)>>1;
tr_js(t,l,t1), tr_js(t+1,t1+1,r);
tr[0][k]=merge(tr[0][t],tr[0][t+1]);
tr[1][k]=merge(tr[1][t],tr[1][t+1]);
}
void update(int k,int t)
{
if (!bz[k]) return;
swap(tr[0][t],tr[1][t]);
swap(tr[0][t+1],tr[1][t+1]);
bz[t]^=bz[k];
bz[t+1]^=bz[k];
bz[k]=0;
}
void xg_single(int k,int l,int r,int x,int z)
{
if (l==r)
{
tr[0][k].s=tr[0][k].sl=tr[0][k].sr=tr[0][k].st=z;
tr[1][k].s=tr[1][k].sl=tr[1][k].sr=tr[1][k].st=-z;
return;
}
int t=k<<1, t1=(l+r)>>1;
update(k,t);
if (x<=t1) xg_single(t,l,t1,x,z); else xg_single(t+1,t1+1,r,x,z);
tr[0][k]=merge(tr[0][t],tr[0][t+1]);
tr[1][k]=merge(tr[1][t],tr[1][t+1]);
}
void xg_many(int k,int l,int r,int x,int y)
{
if (l==x && r==y)
{
swap(tr[0][k],tr[1][k]);
bz[k]^=1;
return;
}
int t=k<<1, t1=(l+r)>>1;
update(k,t);
if (y<=t1) xg_many(t,l,t1,x,y);
else if (x>t1) xg_many(t+1,t1+1,r,x,y);
else xg_many(t,l,t1,x,t1), xg_many(t+1,t1+1,r,t1+1,y);
tr[0][k]=merge(tr[0][t],tr[0][t+1]);
tr[1][k]=merge(tr[1][t],tr[1][t+1]);
}
TR tr_cx(int k,int l,int r,int x,int y)
{
if (l==x && r==y) return tr[0][k];
int t=k<<1, t1=(l+r)>>1;
update(k,t);
if (y<=t1) return tr_cx(t,l,t1,x,y);
else if (x>t1) return tr_cx(t+1,t1+1,r,x,y);
else return merge(tr_cx(t,l,t1,x,t1), tr_cx(t+1,t1+1,r,t1+1,y));
}
int z[maxn][2],z0;
int get(int m,int l,int r)
{
int re=0;
while (m--)
{
TR t=tr_cx(1,1,n,l,r);
if (t.st<=0) break;
re+=t.st;
z[++z0][0]=t.wzi, z[z0][1]=t.wzj;
xg_many(1,1,n,t.wzi,t.wzj);
}
for(; z0; z0--) xg_many(1,1,n,z[z0][0],z[z0][1]);
return re;
}
int m;
int main()
{
scanf("%d",&n);
fo(i,1,n) scanf("%d",&a[i]);
tr_js(1,1,n);
scanf("%d",&m);
while (m--)
{
int ty,l,r,k;
scanf("%d %d %d",&ty,&l,&r);
if (ty==0)
{
xg_single(1,1,n,l,r);
} else
{
scanf("%d",&k);
printf("%d\n",get(k,l,r));
}
}
}