题目大意:
给定
{
t
n
}
\{t_n\}
{tn},求一组
{
x
n
}
,
∀
i
∈
[
1
,
n
]
,
x
i
∈
[
0
,
1
]
\{x_n\},\forall i\in[1,n],x_i\in[0,1]
{xn},∀i∈[1,n],xi∈[0,1]:
max
{
∑
i
=
1
n
∑
j
=
i
n
(
∏
k
=
i
j
x
k
)
−
∑
i
=
1
n
x
i
t
i
}
\max\left\{\sum_{i=1}^n\sum_{j=i}^n\left(\prod_{k=i}^jx_k\right)-\sum_{i=1}^nx_it_i\right\}
max{i=1∑nj=i∑n(k=i∏jxk)−i=1∑nxiti}
并且有
q
q
q组询问,每次给定
x
,
y
x,y
x,y,问若将
t
x
t_x
tx修改为
y
y
y时,答案是多少。每次询问独立,即询问结束后修改会撤销。
n
,
q
≤
3
×
1
0
5
,
1
≤
t
i
,
y
≤
1
0
9
n,q\le3\times10^5,1\le t_i,y\le10^9
n,q≤3×105,1≤ti,y≤109
题解:
考虑不修改怎么做,显然是长为
L
L
L的一段会对答案有
L
(
L
+
1
)
2
−
S
(
L
.
b
e
g
i
n
(
)
,
L
.
e
n
d
(
)
)
\frac{L(L+1)}2-S(L.begin(),L.end())
2L(L+1)−S(L.begin(),L.end())的贡献,然后dp即可。这个显然可以使用斜率优化。
考虑修改怎么做,两种情况,第一种是最终不选这个位置,那么答案是
p
r
e
[
x
−
1
]
+
s
u
f
[
x
+
1
]
pre[x-1]+suf[x+1]
pre[x−1]+suf[x+1]。第二种是钦定这个点选,记作
c
s
t
[
x
]
cst[x]
cst[x],那么答案就是
c
s
t
[
x
]
−
t
[
x
]
+
y
cst[x]-t[x]+y
cst[x]−t[x]+y。
考虑对所有选择
[
L
,
R
]
[L,R]
[L,R]这个区间的方案的收益的最大值
v
v
v,那么
c
s
t
[
x
]
=
max
(
c
s
t
[
x
]
,
v
)
cst[x]=\max(cst[x],v)
cst[x]=max(cst[x],v),考虑分治。
令solve(L,R)为处理[L,R]的子区间。
完全在某半边的递归处理。
跨mid的子区间直接做仍然是不行的,但是可以分成两部分处理:
考虑左半边的点,当选择一个区间包含这个点的时候,右端点实际上是没有用的(只是帮助取得最优值而已)。因此对于每个
L
≤
l
≤
m
i
d
L\le l\le mid
L≤l≤mid,算出最优的
m
i
d
<
r
≤
R
mid<r\le R
mid<r≤R,然后对
[
l
,
m
i
d
]
[l,mid]
[l,mid]取max即可。右半部分同理。
做完啦。
#include<bits/stdc++.h>
#define gc getchar()
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define N 300010
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
int x,ch;while((ch=gc)<'0'||ch>'9');
x=ch^'0';while((ch=gc)>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0');return x;
}
lint pre[N],suf[N],f[N],s[N],cst[N];int t[N],st[N];db A[N];
inline int getdp(lint *dp,int n)
{
rep(i,1,n) s[i]=s[i-1]+t[i];int tp=1;f[0]=0,st[1]=0;
rep(i,1,n)
{
int L=1,R=tp-1,mid=(L+R)>>1;
while(L<=R)
{
if((i+0.5)*(st[mid+1]-st[mid])>A[st[mid+1]]-A[st[mid]]) R=mid-1;
else L=mid+1;mid=(L+R)>>1;
}
dp[i]=f[st[L]]+(i-st[L])*(i-st[L]+1ll)/2-s[i]+s[st[L]],
f[i]=max(f[i-1],dp[i]),A[i]=(db)f[i]+s[i]+i/2.0*i;
while(tp>1&&(A[i]-A[st[tp]])*(st[tp]-st[tp-1])>=(A[st[tp]]-A[st[tp-1]])*(i-st[tp])) tp--;
st[++tp]=i;
}
dp[0]=0;for(int i=1;i<=n;i++) dp[i]=max(dp[i],dp[i-1]);
return 0;
}
lint dp[N];
int solve(int L,int R)
{
if(L==R) return cst[L]=pre[L-1]+suf[R+1]+1-t[R],0;
int mid=(L+R)>>1,tp;solve(L,mid),solve(mid+1,R);
tp=0;
for(int i=L-1;i<mid;i++)
{
A[i]=(db)pre[i]+s[i]+i/2.0*i;
while(tp>1&&(A[i]-A[st[tp]])*(st[tp]-st[tp-1])>=(A[st[tp]]-A[st[tp-1]])*(i-st[tp])) tp--;
st[++tp]=i;
}
for(int i=mid+1;i<=R;i++)
{
int l=1,r=tp-1,mid=(l+r)>>1;
while(l<=r)
{
if((i+0.5)*(st[mid+1]-st[mid])>A[st[mid+1]]-A[st[mid]]) r=mid-1;
else l=mid+1;mid=(l+r)>>1;
}
dp[i]=suf[i+1]+(i-st[l])*(i-st[l]+1ll)/2-s[i]+s[st[l]]+pre[st[l]];
}
cst[R]=max(cst[R],dp[R]);
for(int i=R-1;i>mid;i--) cst[i]=max(cst[i],dp[i]=max(dp[i+1],dp[i]));
tp=0;
for(int i=mid+2;i<=R+1;i++)
{
A[i]=(db)suf[i]-s[i-1]+i/2.0*i;
while(tp>1&&(A[i]-A[st[tp]])*(st[tp]-st[tp-1])>=(A[st[tp]]-A[st[tp-1]])*(i-st[tp])) tp--;
st[++tp]=i;
}
for(int i=L;i<=mid;i++)
{
int l=1,r=tp-1,mid=(l+r)>>1;
while(l<=r)
{
if((i+0.5)*(st[mid+1]-st[mid])>A[st[mid+1]]-A[st[mid]]) r=mid-1;
else l=mid+1;mid=(l+r)>>1;
}
dp[i]=pre[i-1]+(st[l]-i)*(st[l]-i+1ll)/2+s[i-1]-s[st[l]-1]+suf[st[l]];
}
cst[L]=max(cst[L],dp[L]);
for(int i=L+1;i<=mid;i++) cst[i]=max(cst[i],dp[i]=max(dp[i-1],dp[i]));
return 0;
}
int main()
{
int n=inn();rep(i,1,n) t[i]=inn();
getdp(pre,n),reverse(t+1,t+n+1);
getdp(suf,n),reverse(t+1,t+n+1);
reverse(suf+1,suf+n+1);
rep(i,1,n) s[i]=s[i-1]+t[i];
solve(1,n);
for(int q=inn(),x,y;q;q--)
x=inn(),y=inn(),printf("%lld\n",max(0ll,max(pre[x-1]+suf[x+1],cst[x]+t[x]-y)));
return 0;
}