Codeforces Round #622

C2. Skyscrapers (hard version)

题目链接
线段树+分治

#include
using namespace std;
const int maxn = 5e5+7;
int n;
long long a[maxn],b[maxn];
typedef pair<long long,int> SgTreeDataType;
struct treenode
{
  int L , R  ;
  SgTreeDataType mi,lazy;
};

treenode tree[maxn*4];
inline void push_up(int o){
    if(tree[2*o].mi.first==0)tree[2*o].mi={1e9+7,1e9};
    if(tree[2*o+1].mi.first==0)tree[2*o+1].mi={1e9+7,1e9};
    if(tree[2*o].mi.first>tree[2*o+1].mi.first){
        tree[o].mi=tree[2*o+1].mi;
    }else{
        tree[o].mi=tree[2*o].mi;
    }
}

inline void build_tree(int L , int R , int o)
{
    tree[o].L = L , tree[o].R = R;
    if(L==R)
        tree[o].mi={a[L],L};
    if (R > L)
    {
        int mid = (L+R) >> 1;
        build_tree(L,mid,o*2);
        build_tree(mid+1,R,o*2+1);
        push_up(o);
    }
}
inline SgTreeDataType query(int QL,int QR,int o)
{
    int L = tree[o].L , R = tree[o].R;
    if (QL <= L && R <= QR) return tree[o].mi;
    else
    {
        int mid = (L+R)>>1;
        SgTreeDataType mi = {1e9+7,1};
        if (QL <= mid){
            SgTreeDataType res = query(QL,QR,2*o);
            if(res.first<mi.first){
                mi=res;
            }
        }
        if (QR > mid){
            SgTreeDataType res = query(QL,QR,2*o+1);
            if(res.first<mi.first){
                mi=res;
            }
        }
        push_up(o);
        return mi;
    }
}

long long solve(int l,int r){
    if(l>r){
        return 0L;
    }
    if(l==r){
        b[l]=a[l];
        return 1ll*a[l];
    }
    pair<long long,int> mi = query(l,r,1);
    long long sum1 = solve(l,mi.second-1);
    long long sum2 = solve(mi.second+1,r);
    //cout<
    if(1ll*((r-mi.second-1)+1)*mi.first+mi.first+sum1>
       1ll*((mi.second-1-l)+1)*mi.first+mi.first+sum2){
        for(int i=mi.second;i<=r;i++){
            b[i]=mi.first;
        }
        return 1ll*((r-mi.second-1)+1)*mi.first+mi.first+sum1;
    }else{
        for(int i=l;i<=mi.second;i++){
            b[i]=mi.first;
        }
        return 1ll*((mi.second-1-l)+1)*mi.first+mi.first+sum2;
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
    }
    build_tree(1,n,1);
    solve(1,n);
    for(int i=1;i<=n;i++){
        cout<<b[i]<<" ";
    }
    cout<<endl;
}

法2:
显然满足题意的一定是一个单峰序列,于是可以考虑第i个当最高点的时候,左边的最大总和,而这个是可以递推的,因为当mi>=mi-1的时候第i个可以直接取mi加上去,而当mi

#include 
using namespace std;
typedef long long ll;
 
const int maxn = 500000+10;
 
struct Node {
    int val, cnt;
} a[maxn];
 
int m[maxn];
ll f[maxn], g[maxn];
int b[maxn];
 
int main() {
    int n;
    scanf("%d", &n);
    for(int i=1; i<=n; i++)
        scanf("%d", &m[i]);
    int k = 0;
    for(int i=1; i<=n; i++) {
        if(m[i]>=m[i-1]) {
            a[++k] = (Node){m[i], 1};
            f[i] = f[i-1]+m[i];
        }
        else {
            ll sum = 0;
            int num = 0;
            while(k>=1 && a[k].val>=m[i]) {
                sum += (ll)a[k].val*a[k].cnt;
                num += a[k].cnt; k--;
            }
            a[++k] = (Node){m[i], num+1};
            f[i] = f[i-1]-sum+(ll)(num+1)*m[i];
        }
    }
    k = 0;
    for(int i=n; i>=1; i--) {
        if(m[i]>=m[i+1]) {
            a[++k] = (Node){m[i], 1};
            g[i] = g[i+1]+m[i];
        }
        else {
            ll sum = 0;
            int num = 0;
            while(k>=1 && a[k].val>=m[i]) {
                sum += (ll)a[k].val*a[k].cnt;
                num += a[k].cnt; k--;
            }
            a[++k] = (Node){m[i], num+1};
            g[i] = g[i+1]-sum+(ll)(num+1)*m[i];
        }
    }
    int id = 1;
    for(int i=2; i<=n; i++) {
        if(f[i]+g[i]-m[i]>f[id]+g[id]-m[id])
            id = i;
    }
    b[id] = m[id];
    for(int i=id-1; i>=1; i--)
        b[i] = min(m[i], b[i+1]);
    for(int i=id+1; i<=n; i++)
        b[i] = min(m[i], b[i-1]);
    for(int i=1; i<=n; i++)
        printf("%d ", b[i]);
    printf("\n");
    return 0;
}

你可能感兴趣的:(补题)