CF1539F

题目

给定数组(a),对于某个元素(a_i)和区间([l,r])满足(lle i le r)。如果将(a_l,a_{l+1},...a_r)排序后,原(a_i)在排序后的新位置为(j)(值相同是可以任意排序),那么(a_i)的奇异值为(|j-lfloorfrac{l+r+1}{2} floor|)。问每个元素最大的奇异值是多少。

题解

假设对于某个元素(a_i)和区间([l,r])满足(lle i le r),如果排完序后(a_i)(lfloorfrac{l+r+1}{2} floor)的左侧,那么它的排位应该尽可能地靠左;否则要尽可能的靠右。因此可以算两遍,假设(a_i)在左侧算一次结果,在右侧算一次结果,两次取最大值,这样就可以去掉绝对值。

假设(a_i)在左侧,因为(a_i)的排位要尽可能地小,所以它的排位就是区间([l,r])中严格小于(a_i)的值的个数加1。这个个数可以通过维护前缀和快速计算。那么奇异值为(d=lfloorfrac{r-(l-1)}{2}+1 floor-(pre[r]-pre[l-1]+1))。整理后可得

[d=lfloor frac{(r-2pre[r]) - (l-2pre[l])}{2} floor ]

所以要使(d)最大,只需使((r-2pre[r]) - (l-2pre[l]))最大,直接用线段树维护这个值,然后区间询问左部分的最小值和右部分的最大值即可。

同理假设(a_i)在右侧,因为(a_i)的排位要尽可能地大,所以它的排位就是区间([l,r])中小于等于(a_i)的值的个数,奇异值为(d=(pre[r]-pre[l-1])-lfloorfrac{r-(l-1)}{2}+1 floor),整理后得

[d=lceil frac{(r-2pre[r])-(l-2pre[r])-2}{2} ceil ]

至于如何维护这个前缀和,只需按照值从小到大更新计算即可。

#include <bits/stdc++.h>

#define endl '
'
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define mp make_pair
#define seteps(N) fixed << setprecision(N) 
typedef long long ll;

using namespace std;
/*-----------------------------------------------------------------*/

ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
#define INF 0x3f3f3f3f

const int N = 2e5 + 10;
const double eps = 1e-5;

int mi[N << 2];
int mx[N << 2];
int lazy[N << 2];

void init(int l, int r, int rt) {
    lazy[rt] = mi[rt] = mx[rt] = 0;
    if(l == r) return ;
    int mid = (l + r) / 2;
    init(l, mid, rt << 1);
    init(mid + 1, r, rt << 1 | 1);
}

void pushdown(int rt) {
    if(lazy[rt]) {
        lazy[rt << 1] += lazy[rt];
        lazy[rt << 1 | 1] += lazy[rt];
        mi[rt << 1] += lazy[rt];
        mi[rt << 1 | 1] += lazy[rt];
        mx[rt << 1] += lazy[rt];
        mx[rt << 1 | 1] += lazy[rt];
        lazy[rt] = 0;
    }
}

void upd(int l, int r, int L, int R, int val, int rt) {
    if(l >= L && r <= R) {
        mi[rt] += val;
        mx[rt] += val;
        lazy[rt] += val;
        return ;
    }    
    pushdown(rt);
    int mid = (l + r) / 2;
    if(L <= mid) upd(l, mid, L, R, val, rt << 1);
    if(R > mid) upd(mid + 1, r, L, R, val, rt << 1 | 1);
    mi[rt] = min(mi[rt << 1], mi[rt << 1 | 1]);
    mx[rt] = max(mx[rt << 1], mx[rt << 1 | 1]);
}

int quemi(int l, int r, int L, int R, int rt) {
    if(l >= L && r <= R) {
        return min(0, mi[rt]);
    }    
    int res = 0;
    pushdown(rt);
    int mid = (l + r) / 2;
    if(L <= mid) res = min(res, quemi(l, mid, L, R, rt << 1));
    if(R > mid) res = min(res, quemi(mid + 1, r, L, R, rt << 1 | 1));
    mi[rt] = min(mi[rt << 1], mi[rt << 1 | 1]);
    return res;
}

int quemx(int l, int r, int L, int R, int rt) {
    if(l >= L && r <= R) {
        return mx[rt];
    }    
    int res = -INF;
    pushdown(rt);
    int mid = (l + r) / 2;
    if(L <= mid) res = max(res, quemx(l, mid, L, R, rt << 1));
    if(R > mid) res = max(res, quemx(mid + 1, r, L, R, rt << 1 | 1));
    mx[rt] = max(mx[rt << 1], mx[rt << 1 | 1]);
    return res;
}


int ans[N];

vector<int> pos[N];
int main() {
    IOS;
    int n;
    cin >> n;
    for(int i = 1; i <= n; i++) {
        int x;
        cin >> x;
        pos[x].push_back(i);
        upd(1, n, i, i, i, 1);
    }
    for(int i = 1; i < N; i++) {
        for(int p : pos[i]) {
            int d = quemx(1, n, p, n, 1) - quemi(1, n, 1, p, 1);
            if(d < 0) continue;
            d = d / 2;
            ans[p] = max(ans[p], d);
        }
        for(int p : pos[i]) {
            upd(1, n, p, n, -2, 1);
        }
    }

    init(1, n, 1);
    for(int i = 1; i <= n; i++) {
        upd(1, n, i, i, -i, 1);
    }
    for(int i = 1; i < N; i++) {
        for(int p : pos[i]) {
            upd(1, n, p, n, 2, 1);
        }
        for(int p : pos[i]) {
            int d = quemx(1, n, p, n, 1) - quemi(1, n, 1, p, 1) - 2;
            if(d < 0) continue;
            d = d / 2 + (d % 2 != 0);
            ans[p] = max(ans[p], d);
        }
    }
    for(int i = 1; i <= n; i++) cout << ans[i] << " 
"[i == n];
}
原文地址:https://www.cnblogs.com/limil/p/15332482.html