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];
    }
    
  • 相关阅读:
    随机森林算法参数调优
    BAYES和朴素BAYES
    阿里云 金融接口 token PHP
    PHP mysql 按时间分组 表格table 跨度 rowspan
    MySql按周,按月,按日分组统计数据
    PHP 获取今日、昨日、本周、上周、本月的等等常用的起始时间戳和结束时间戳的时间处理类
    thinkphp5 tp5 会话控制 session 登录 退出 检查检验登录 判断是否应该跳转到上次url
    微信 模板消息
    php 腾讯 地图 api 计算 坐标 两点 距离 微信 网页 WebService API
    php添加http头禁止浏览器缓存
  • 原文地址:https://www.cnblogs.com/limil/p/15332482.html
Copyright © 2011-2022 走看看