https://codeforces.com/problemset/problem/1313/C2
一开始写了个假做法写到200+行。。。突然发现巨水。。。
目标是要算出以i为顶峰的答案
就是从i向左,向右=a[i]的区间+到某个比他小的地方j,被那个a[j]限制了,之后就是从j一路往下的答案
这个从某个位置一路往下的答案可以预处理
求出比他小的左右最近的地方在哪就行了,单调栈,线段树都行
我对a[i]离散化了,然后没调用num[a[i]]计算也pp了。。。还好没用紫名号打。。。
#include
using namespace std;
const int maxl=5e5+10;
int n,cnt,tot,ansid;
int a[maxl],inia[maxl],num[maxl],resa[maxl];
int pre[maxl],nxt[maxl];
long long presum[maxl],nxtsum[maxl];
long long ans;
struct node
{
int l,r,mi,mx;
}tree[maxl<<2];
inline void build_tot(int k,int l,int r,int ini)
{
tree[k].l=l;tree[k].r=r;
tree[k].mi=tree[k].mx=ini;
if(l==r)
return;
int mid=(l+r)>>1;
build_tot(k<<1,l,mid,ini);
build_tot(k<<1|1,mid+1,r,ini);
}
inline int qry_mx(int k,int l,int r)
{
if(tree[k].l==l && tree[k].r==r)
return tree[k].mx;
int ret=0;
int mid=(tree[k].l+tree[k].r)>>1;
if(r<=mid)
ret=qry_mx(k<<1,l,r);
else if(l>mid)
ret=qry_mx(k<<1|1,l,r);
else
ret=max(qry_mx(k<<1,l,mid),qry_mx(k<<1|1,mid+1,r));
return ret;
}
inline int qry_mi(int k,int l,int r)
{
if(tree[k].l==l && tree[k].r==r)
return tree[k].mi;
int ret=0;
int mid=(tree[k].l+tree[k].r)>>1;
if(r<=mid)
ret=qry_mi(k<<1,l,r);
else if(l>mid)
ret=qry_mi(k<<1|1,l,r);
else
ret=min(qry_mi(k<<1,l,mid),qry_mi(k<<1|1,mid+1,r));
return ret;
}
inline void eql(int k,int l,int x)
{
if(tree[k].l==tree[k].r)
{
tree[k].mx=tree[k].mi=x;
return;
}
int mid=(tree[k].l+tree[k].r)>>1;
if(l<=mid)
eql(k<<1,l,x);
else
eql(k<<1|1,l,x);
tree[k].mx=max(tree[k<<1].mx,tree[k<<1|1].mx);
tree[k].mi=min(tree[k<<1].mi,tree[k<<1|1].mi);
}
inline void prework()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),num[i]=a[i];
sort(num+1,num+1+n);
tot=unique(num+1,num+1+n)-num-1;
for(int i=1;i<=n;i++)
a[i]=lower_bound(num+1,num+1+tot,a[i])-num;
build_tot(1,1,tot,0);
for(int i=1;i<=n;i++)
{
if(a[i]>1)
pre[i]=qry_mx(1,1,a[i]-1);
eql(1,a[i],i);
presum[i]=1ll*(i-pre[i])*num[a[i]]+presum[pre[i]];
}
build_tot(1,1,tot,n+1);
for(int i=n;i>=1;i--)
{
if(a[i]>1)
nxt[i]=qry_mi(1,1,a[i]-1);
if(nxt[i]==0)
nxt[i]=n+1;
eql(1,a[i],i);
nxtsum[i]=1ll*(nxt[i]-i)*num[a[i]]+nxtsum[nxt[i]];
}
}
inline void mainwork()
{
long long tmp;
for(int i=1;i<=n;i++)
{
tmp=1ll*(nxt[i]-pre[i]-1)*num[a[i]];
tmp+=presum[pre[i]]+nxtsum[nxt[i]];
if(tmp>ans)
{
ans=tmp;
ansid=i;
}
}
}
inline void print()
{
int now=num[a[ansid]];
for(int i=ansid;i>=1;i--)
{
now=min(num[a[i]],now);
resa[i]=now;
}
now=num[a[ansid]];
for(int i=ansid;i<=n;i++)
{
now=min(num[a[i]],now);
resa[i]=now;
}
for(int i=1;i<=n;i++)
printf("%d%c",resa[i],(i==n)?'\n':' ');
}
int main()
{
prework();
mainwork();
print();
return 0;
}