CF1539F - Strange Array(线段树)

题目

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

题解

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

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

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

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

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

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

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

#include <bits/stdc++.h>

#define endl '\n'
#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] << " \n"[i == n];
}
上一篇:(2019多校第一场)hdu6588 Function


下一篇:[康复计划]-数论基础