• 5308: [Zjoi2018]胖


    5308: [Zjoi2018]胖

    链接

    分析:

      题目转化为一个点可以更新多少个点,一个点可以更新的点一定是一个区间,考虑二分左右端点确定这个区间。

      设当前点是x,向右二分一个点y,如果x可以更新到y,那么在x~y之间的所有关键点(存在宫殿往这边的点)到y的距离小于x到y的距离,以及y~2*y-x之间的关键点到y的距离小于x到y的距离。

      当然一个点可能同时被两个点更新,那么让最靠左的点更新它。

    代码:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<cctype>
    #include<set>
    #include<queue>
    #include<vector>
    #include<map>
    using namespace std;
    typedef long long LL;
    
    inline int read() {
        int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
        for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
    }
    
    const int N = 200005;
    int Log[N], n, m, k;
    LL dis[N];
    struct Node {
        int p; LL l;
        Node() {}
        Node(int _p,LL _l) { p = _p, l = _l; }
        bool operator < (const Node &A) const { return p < A.p; }
    }a[N];
    struct ST{
        LL f[20][N];
        void init() {
            for (int i = 1; i <= k; ++i) f[0][i] = a[i].l;
            for (int j = 1; j <= Log[k]; ++j) 
                for (int i = 1; i + (1 << j) - 1 <= k; ++i) 
                    f[j][i] = min(f[j - 1][i], f[j - 1][i + (1 << (j - 1))]);
        }
        LL query(int l,int r) {
            l = max(1, l), r = min(r, n);
            l = lower_bound(a + 1, a + k + 1, Node(l, 0)) - a;
            r = upper_bound(a + 1, a + k + 1, Node(r, 0)) - a - 1;
            if (l > r) return 1e18;
            int k = Log[r - l + 1];
            return min(f[k][l], f[k][r - (1 << k) + 1]);
        }
    }L, R;
    
    bool check1(int x,int y) { // [2 * y - x + 1, y, x]
        if (x == y) return true;
        LL a = L.query(2 * y - x + 1, y) + dis[y];
        LL b = R.query(y, x - 1) - dis[y];
        LL c = R.query(x, x) - dis[y];
        if (a <= c || b <= c) return false;
        if (2 * y - x >= 1) return L.query(2 * y - x, 2 * y - x) + dis[y] > c; // 如果距离相同,优先给左边的点 
        return true;
    }
    int findL(int x) {
        int l = 1, r = x, ans = 0;
        while (l <= r) {
            int mid = (l + r) >> 1;
            if (check1(x, mid)) r = mid - 1, ans = mid;
            else l = mid + 1;
        }
        return ans;
    }
    bool check2(int x,int y) { // [x, y, 2 * y - x - 1]
        if (x == y) return true;
        LL a = L.query(x + 1, y) + dis[y];
        LL b = R.query(y, 2 * y - x - 1) - dis[y];
        LL c = L.query(x, x) + dis[y];
        if (a <= c || b <= c) return false;
        if (2 * y - x <= n) return R.query(2 * y - x, 2 * y - x) - dis[y] >= c;
        return true;
    }
    int findR(int x) {
        int l = x, r = n, ans = 0;
        while (l <= r) {
            int mid = (l + r) >> 1;
            if (check2(x, mid)) l = mid + 1, ans = mid;
            else r = mid - 1;
        }
        return ans;
    }
    int main() {
        n = read(), m = read();
        for (int i = 2; i <= n; ++i) Log[i] = Log[i >> 1] + 1;
        for (int i = 2; i <= n; ++i) dis[i] = dis[i - 1] + read();
        while (m --) {
            LL ans = 0;
            k = read();
            for (int i = 1; i <= k; ++i) a[i].p = read(), a[i].l = read();
            sort(a + 1, a + k + 1);
            for (int i = 1; i <= k; ++i) a[i].l -= dis[a[i].p]; L.init();
            for (int i = 1; i <= k; ++i) a[i].l += dis[a[i].p] * 2; R.init();
            for (int i = 1; i <= k; ++i) ans += findR(a[i].p) - findL(a[i].p) + 1;
            printf("%lld
    ", ans);
        }
        return 0;
    }
  • 相关阅读:
    malloc
    排序算法学习笔记(三)-- 快速排序
    排序算法学习笔记(二)-- 归并排序
    排序算法学习笔记(一)-- 冒泡排序,选择排序,插入排序,希尔排序
    网络协议笔记
    域名和IP地址并用的理由
    WebSocket协议介绍
    Ajax概念
    共享密钥加密、公开密钥加密及HTTPS混合加密
    HTTP缺点
  • 原文地址:https://www.cnblogs.com/mjtcn/p/10492085.html
Copyright © 2020-2023  润新知