zoukankan      html  css  js  c++  java
  • 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];
    }
    
  • 相关阅读:
    MVC调用SVC无法找到资源解决问题
    动态更改iframe src
    http改成https wcf 配置更改
    Nuget 管理报repositories.config 访问路径被拒绝 解决办法
    如何在水晶报表中动态添加字段
    VS2.0控件之日历《Calendar》C#
    C#操作Excel全源码
    如何向水晶报表数据源中的存储过程传参数……
    公式的典型用途
    水晶报表公式使用必读
  • 原文地址:https://www.cnblogs.com/limil/p/15332482.html
Copyright © 2011-2022 走看看