真心好難,代碼不好寫。
最後算是抄的clairs的代碼。
考慮分塊,每塊維護兩個標記ts,tdts,td。
那麼對於塊中一個位置ii,它的實際值爲i×td+ts+vii×td+ts+vi。
修改的時候,對於整塊,直接打標記,對於零散的暴力修改,然後重構凸殼,時間複雜度O(n√)O(n)。
查詢的時候在凸殼上二分即可,時間複雜度O(n√logn)O(nlogn)。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=120006;
const ll inf=1ll<<60;
inline ll read()
{
ll ans,f=1;char ch;
while((ch=getchar())<'0'||ch>'9') if (ch=='-') f=-1;ans=ch-'0';
while((ch=getchar())>='0'&&ch<='9') ans=ans*10+ch-'0';
return ans*f;
}
int n,m,block,num,pos[N],st[N],en[N];
ll sum[N];
ll *v=sum;
double xielv(int i,int j)
{
return (double)(sum[i]-sum[j])/(double)(j-i);
}
struct aa
{
int q[605],tot;
ll add,tag;
ll query()
{
int mid,lt=2,rt=tot,ans=q[1];
while (lt<=rt)
{
mid=(lt+rt)>>1;
if (xielv(q[mid-1],q[mid])<tag) ans=q[mid],lt=mid+1;
else rt=mid-1;
}
return sum[ans]+tag*ans+add;
}//ok
}g[605];
void build(int x)
{
int &tot=g[x].tot;tot=0;
for (int i=st[x];i<=en[x];i++)
{
while (tot>=2 &&
xielv(g[x].q[tot-1],g[x].q[tot])>=xielv(g[x].q[tot],i)
) tot--;
g[x].q[++tot]=i;
}
}//ok
void init()
{
n=read();
ll x;
block=sqrt(n);
num=block+(block*block!=n);
for (int i=1;i<=n;i++) pos[i]=(i-1)/block+1;
for(int i=1;i<=n;i++)en[pos[i]]=i;
for(int i=n;i;i--)st[pos[i]]=i;
for (int i=1;i<=n;i++)
{
x=read();
sum[i]=x+sum[i-1];
}
for (int i=1;i<=num;i++) build(i);
}//ok
inline void change(int x,int y,ll s,ll d){
if(pos[x]==pos[y]){
for(int i=x;i<=y;i++)v[i]+=s+d*i;
build(pos[x]);
return;
}
for(int i=pos[x]+1;i<pos[y];i++)g[i].add+=s,g[i].tag+=d;
for(int i=en[pos[x]];i>=x;i--)v[i]+=s+d*i;
build(pos[x]);
for(int i=st[pos[y]];i<=y;i++)v[i]+=s+d*i;
build(pos[y]);
}
inline void updata(){
int x,y;ll z;
x=read(),y=read(),z=read();
change(x,y,z*(1-x),z);
if(y<n)change(y+1,n,z*(y-x+1),0);
}
inline void up(ll&a,ll b){if(a<b)a=b;}
inline ll query(){
int x=read(),y=read();
ll t=-(1LL<<62);
if(pos[x]==pos[y]){
for(int i=x;i<=y;i++)up(t,g[pos[i]].tag*i+g[pos[i]].add+v[i]);
return t;
}
for(int i=pos[x]+1;i<pos[y];i++)up(t,g[i].query());
for(int i=en[pos[x]];i>=x;i--)up(t,g[pos[i]].tag*i+g[pos[i]].add+v[i]);
for(int i=st[pos[y]];i<=y;i++)up(t,g[pos[i]].tag*i+g[pos[i]].add+v[i]);
return t;
}
int main()
{
init();
int op;m=read();
while (m--)
{
op=read();
if (op==0) updata();
else printf("%lld\n",query());
}
return 0;
}
總結
1:注意變量等的命名,不要出現重複,例如ll類型和ll左端點不要重複。
2:這裏用凸包,其實就是類似於斜率優化的式子,(就是設i<j,j優於i這種情況,推出的式子)也包括那些性質。
3:凸包就是在這些不能一維表示,然後須用二維,但是二維難以取區間最優值,就轉化爲凸包來解二維(有兩個和i有關量的乘號)求。
4:此題思路須再整理!再分析!(今天太晚了。。)