codeforces 1313 C2 Skyscrapers (hard version) (單調佇列)
阿新 • • 發佈:2020-10-15
相較於 easy version ,本題規模擴大到 50w
考慮優化,
對於每個高樓,我們要找的其實是最靠近且比這座樓矮的樓,
中間的樓都建成這座高樓的高度
所以使用單調佇列,求出每座高樓的字首和與字尾和,
再掃一遍所有高樓,找到樓高最大的答案
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<cmath> #include<stack> #include<queue> using namespace std; typedef long long ll; const int maxn = 500010; int n; ll a[maxn],pre[maxn],suf[maxn],p[maxn],q[maxn],b[maxn],l[maxn],r[maxn]; ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; } int main(){ n = read(); for(int i=1;i<=n;++i) a[i] = read(); int tail = 0; ll sum = 0; for(int i=1;i<=n;++i){ while(q[tail] > a[i] && tail > 0){ sum -= 1ll * (p[tail] - p[tail-1]) * q[tail]; --tail; } l[i] = p[tail]; q[++tail] = a[i]; p[tail] = i; sum += 1ll * (p[tail] - p[tail-1]) * a[i]; pre[i] = sum; } tail = 0; sum = 0; memset(q,0,sizeof(q)); memset(p,0,sizeof(p)); p[0] = n+1; for(int i=n;i>=1;--i){ while(q[tail] > a[i] && tail > 0){ sum -= 1ll * (p[tail-1] - p[tail]) * q[tail]; --tail; } r[i] = p[tail]; q[++tail] = a[i]; p[tail] = i; sum += 1ll * (p[tail-1] - p[tail]) * a[i]; suf[i] = sum - a[i]; } ll ans = 0; int pos; for(int i=1;i<=n;++i){ if(pre[i] + suf[i] > ans){ ans = pre[i] + suf[i]; pos = i; } } ll h = a[pos]; b[pos] = a[pos]; for(int i=pos-1;i>=1;--i){ if(a[i] < h) h = a[i]; b[i] = h; } h = a[pos]; for(int i=pos+1;i<=n;++i){ if(a[i] < h) h = a[i]; b[i] = h; } for(int i=1;i<=n;i++){ printf("%lld ",b[i]); }printf("\n"); return 0; }