• CF765F Souvenirs


    题目链接

    Solution

    首先将询问离线,按照右端点从小到大排序。假设我们已经知道了 ([l,r-1]) 的答案,现在将 (a_r) 加入更新答案。显然只需要考虑 (a_r) 对答案的贡献。同时建立线段树,(seg_i) 维护 (i) 位置到 (r) 位置的答案。

    (a_r) 贡献答案只有 (2) 种情况:前面存在一个数 (a_j > a_r),则用 (a_j - a_r)(seg_{1-j}) 进行更新;前面存在一个数 (a_j < a_r),则用 (a_r - a_j)(seg_{1-j}) 进行更新。

    因为这两种情况本质相同,所以我们只讲解其中的第一种情况。考虑用一种最暴力的办法:对于每个 (r),找到其前面第一个大于它的数,更新答案;继续找第二个...很显然这样做会 T 到飞起。那么这种暴力可以优化吗?答案是可以的,使用主席树维护权值区间的最大位置。每次使用主席树查找上一个比它大的数。

    但是这样还不够,需要优化。如果 (a_x>a_r,a_z>a_r(z<x<r)),那么如果 (a_x-a_z<a_z-a_r)(a_z-a_r) 将不会对答案产生任何贡献。

    所以我们就找到了权值的一个边界 (frac{a_r+a_x}{2})。这样每次除下去,复杂度会变成 (log)

    Code

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define int long long
    using namespace std;
    
    const int N = 333333, INF = 1e18;
    struct que { int l, r, id; } q[N];
    int n, m, pos, len, now = 1, a[N], b[N];
    int minn[N << 5], tag[N << 5], hav[N << 5], maxx[N << 5], L[N << 5], R[N << 5], t[N], ans[N], cnt = 0, last = 0;
    
    struct SegmentTree
    {
        void push_up(int x) { minn[x] = min(min(minn[x], minn[x * 2]), minn[x * 2 + 1]); }
        void push_down(int x)
        {
            tag[x * 2] = min(tag[x * 2], tag[x]);
            tag[x * 2 + 1] = min(tag[x * 2 + 1], tag[x]);
            minn[x] = min(minn[x], tag[x]);
            minn[x * 2] = min(minn[x * 2], tag[x * 2]);
            minn[x * 2 + 1] = min(minn[x * 2 + 1], tag[x * 2 + 1]);
        }
        void update(int x, int l, int r, int stdl, int stdr, int k)
        {
            if(l > stdr || r < stdl) return ;
            if(stdl <= l && stdr >= r)
            {
                tag[x] = min(tag[x], k);
                minn[x] = min(minn[x], tag[x]);
                push_down(x);
                return ;
            }
            int mid = (l + r) >> 1;
            push_down(x);
            update(x * 2, l, mid, stdl, stdr, k);
            update(x * 2 + 1, mid + 1, r, stdl, stdr, k);
            push_up(x);
        }
        int query(int x, int l, int r, int stdl, int stdr)
        {
            if(l > stdr || r < stdl) return INF;
            if(stdl <= l && stdr >= r) return minn[x];
            int mid = (l + r) >> 1;
            push_down(x);
            return min(query(x * 2, l, mid, stdl, stdr), query(x * 2 + 1, mid + 1, r, stdl, stdr));
            push_up(x);
        }
    } Tree1;
    
    struct ChairmanTree
    {
        int build(int l, int r)
        {
            int root = ++cnt;
            if(l < r)
            {
                int mid = (l + r) >> 1;
                L[root] = build(l, mid);
                R[root] = build(mid + 1, r);
            }
            return root;
        }
        int update(int pre, int l, int r, int x, int k)
        {
            int root = ++cnt;
            L[root] = L[pre], R[root] = R[pre];
            maxx[root] = max(maxx[pre], k);
            if(l < r)
            {
                int mid = (l + r) >> 1;
                if(x <= mid) L[root] = update(L[pre], l, mid, x, k);
                else R[root] = update(R[pre], mid + 1, r, x, k);
            }
            return root;
        }
        int query(int x, int l, int r, int stdl, int stdr)
        {
            if(b[l] > stdr || b[r] < stdl) return 0;
            if(stdl <= b[l] && stdr >= b[r]) return maxx[x];
            int mid = (l + r) >> 1;
            return max(query(L[x], l, mid, stdl, stdr), query(R[x], mid + 1, r, stdl, stdr));
        }
    } Tree2;
    
    bool cmp(que a, que b) { return a.r < b.r; }
    
    signed main()
    {
        scanf("%lld", &n);
        memset(hav, 0, sizeof(hav));
        memset(maxx, 0, sizeof(maxx));
        for(int i = 0; i < N << 5; i++) tag[i] = minn[i] = 1e18;
        for(int i = 1; i <= n; i++) scanf("%lld", &a[i]), b[i] = a[i];
        scanf("%lld", &m);
        for(int i = 1; i <= m; i++) scanf("%lld%lld", &q[i].l, &q[i].r), q[i].id = i;
        sort(q + 1, q + m + 1, cmp);
        sort(b + 1, b + n + 1);
        t[0] = Tree2.build(1, n);
        b[0] = 0;
        for(int i = 1; i <= n; i++) a[i] = lower_bound(b + 1, b + n + 1, a[i]) - b;
        for(int i = 1; i <= n; i++)
        {
            pos = 0;
            pos = Tree2.query(t[i - 1], 1, n, 0, b[a[i]]);
            if(pos != 0) Tree1.update(1, 1, n, 1, pos, b[a[i]] - b[a[pos]]);
            while(pos)
            {
                pos = Tree2.query(t[pos - 1], 1, n, (b[a[pos]] + b[a[i]]) / 2 + 1, b[a[i]]);
                if(pos <= 0) break;
                Tree1.update(1, 1, n, 1, pos, b[a[i]] - b[a[pos]]);
            }
            pos = 0;
            pos = Tree2.query(t[i - 1], 1, n, b[a[i]], b[n]);
            if(pos != 0) Tree1.update(1, 1, n, 1, pos, b[a[pos]] - b[a[i]]);
            while(pos)
            {
                if((b[a[pos]] + b[a[i]]) % 2 == 0) len = (b[a[pos]] + b[a[i]]) / 2 - 1;
                else len = (b[a[pos]] + b[a[i]]) / 2;
                pos = Tree2.query(t[pos - 1], 1, n, b[a[i]], len);
                if(pos <= 0) break;
                Tree1.update(1, 1, n, 1, pos, b[a[pos]] - b[a[i]]);
            }
            while(q[now].r <= i && now <= m)
            {
                if(q[now].r == i) ans[q[now].id] = Tree1.query(1, 1, n, q[now].l, q[now].r);
                now++;
            }
            t[i] = Tree2.update(t[i - 1], 1, n, a[i], i);
        }
        for(int i = 1; i <= m; i++) printf("%lld
    ", ans[i]);
        return 0;
    }
    
  • 相关阅读:
    Oracle导出导入表空间创建
    ASP.NET 缓存 SqlCacheDependency 监视数据库表变化 让缓存更新的更及时更提高节能
    Silverlight在添加WCF服务引用时报错
    springboot中如何动态更换 配置文件 spring.profiles.active
    maven之根据profile动态切换resource
    java synchronized 关键字的锁升级过程
    子类中的方法和父类同名,但是参数不同,是重写(overload)不是覆盖(override)
    Java的协变(extends)和逆变(super),说白了都是子类的实例赋值给父类的变量
    Mybatis缓存
    [转]Spring MVC之 @PathVariable @CookieValue@RequestParam @RequestBody @RequestHeader@SessionAttributes, @ModelAttribute
  • 原文地址:https://www.cnblogs.com/Andy-park/p/13763485.html
Copyright © 2020-2023  润新知