• ZJOI2018 胖


    ZJOI2018 胖

    题意:

    题目传送门

    题解:

    时隔一年才来做这道题的我真是太菜了……
    我们将修建的道路所连接的点称作关键点,那么考虑每一条道路能够更新的点一定是一段连续的区间([L, R])(sum_i R_i - L_i + 1)就是题目的答案。于是我们考虑如何求出每一个关键点更新的区间([L, R])。很容易想到的是二分,由于右端点与左端点的方法类似,我们就以左端点为例。

    假设当前二分到的点为(p),那么如果(p)会被当前关键点(x)更新到,那么一定满足([p - d, p + d])(d)(x)(p)的下标差值,即(| x - p |))这个区间内没有关键点到达(p)的距离比(x)更小。如果不满足,那么更新这个点(p)的一定是另一个关键点。于是我们转而考虑如何维护区间最小值,可以用线段树,但是常数太大,我们可以用(ST)表来完成。每次预处理为(O(k log(k))),查询(O(1)),这样总复杂度为(O(k log(k)))

    另外还要考虑到如果([p - d, p + d])这个区间关键点到达(p)的距离等于(x)(p)的距离时,这个贡献只能算(1)次,显然如果两个关键点到(p)的下标差值不同,那么贡献一定是算在下标差值小的关键点上,如果这个值也相同,那么随便选一个都行,只要答案统计时不重复就行了。

    Code

    #pragma GCC optimize (2,"inline","Ofast")
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 2e5 + 50;
    const ll INF = 1e16;
    
    int n, m, k;
    int w[N], Lg[N];
    ll sum[N], st1[N][21], st2[N][21], lmn[N], rmn[N];
    struct edge {
      int pos, l;
      bool operator < (const edge &rhs) const {
        return pos < rhs.pos;
      }
    }E[N];
    
    int Min(int x, int y) {
      if(rmn[x] == rmn[y]) return min(x, y);
      return rmn[x] < rmn[y] ? x : y;
    }
    
    int Max(int x, int y) {
      if(lmn[x] == lmn[y]) return max(x, y);
      return lmn[x] > lmn[y] ? x : y;
    }
    
    int GetMn(int l, int r) {
      int G = Lg[r - l + 1];
      return Min(st2[l][G], st2[r - (1 << G) + 1][G]);
    }
    
    int GetmMx(int l, int r) {
      int G = Lg[r - l + 1];
      return Max(st1[l][G], st1[r - (1 << G) + 1][G]);
    }
    
    void Init() {
      sort(E + 1, E + 1 + k);
      for(int i = 1; i <= k; i++) {
        lmn[i] = sum[E[i].pos] - E[i].l; rmn[i] = sum[E[i].pos] + E[i].l;
        st1[i][0] = st2[i][0] = i;
      }
      for(int j = 1; (1 << j) <= k; j++) {
        for(int i = 1; i + (1 << j) - 1 <= k; i++) {
          st1[i][j] = Max(st1[i][j - 1], st1[i + (1 << (j - 1))][j - 1]);
          st2[i][j] = Min(st2[i][j - 1], st2[i + (1 << (j - 1))][j - 1]);
        }
      }
    }
    
    int Judge(int a, int b, int p) {
      ll len1 = E[a].l + abs(sum[p] - sum[E[a].pos]), len2 = E[b].l + abs(sum[p] - sum[E[b].pos]);
      if(len1 != len2) return len1 < len2 ? a : b;
      int dis1 = abs(E[a].pos - p), dis2 = abs(E[b].pos - p);
      if(dis1 != dis2) return dis1 < dis2 ? a : b;
      return min(a, b);
    }
    
    int Check(int a, int p) {
      int dis = abs(E[a].pos - p), dom = a;
      edge e1 = (edge) { p, 0 }, e2 = (edge) { p + dis, 0 }, e3 = (edge) { p - dis, 0};
      int l = lower_bound(E + 1, E + 1 + k, e3) - E, r = upper_bound(E + 1, E + 1 + k, e2) - E - 1, mid = upper_bound(E + 1, E + 1 + k, e1) - E - 1;
      if(l <= mid) dom = Judge(dom, GetMx(l, mid), p);
      if(mid < r) dom = Judge(dom, GetMn(mid + 1, r), p);
      return dom == a;
    }
    
    void Solve() {
      ll ans = 0;
      for(int i = 1; i <= k; i++) {
        int l = 1, r = E[i].pos, ansl = E[i].pos, ansr = E[i].pos;
        while(l <= r) {
          int mid = (l + r) >> 1;
          if(Check(i, mid)) r = mid - 1, ansl = mid;
          else l = mid + 1;
        }
        l = E[i].pos, r = n;
        while(l <= r) {
          int mid = (l + r) >> 1;
          if(Check(i, mid)) l = mid + 1, ansr = mid;
          else r = mid - 1;
        }
        ans += ansr - ansl + 1;
      }
      printf("%lld
    ", ans);
    }
    
    int main() {
      scanf("%d%d", &n, &m);
      for(int i = 2; i <= n; i++) Lg[i] = Lg[i >> 1] + 1;
      for(int i = 2; i <= n; i++) scanf("%d", &w[i]), sum[i] = sum[i - 1] + w[i];
      for(int i = 1; i <= m; i++) {
        scanf("%d", &k);
        for(int j = 1; j <= k; j++) scanf("%d%d", &E[j].pos, &E[j].l);
        Init(); Solve();
      }
      return 0;
    }
    
  • 相关阅读:
    vue 使用 <iframe> 嵌入网页 地址实现动态配置
    vue 视频播放 vue-video-player
    vue 实现自定义序号, 并且翻页序号累加。
    关于 vue 使用 Handsontable 表格数据导出
    node.js Stream流的使用
    手把手教如何搭建node+egg项目 引入Sequelize
    实现 通过数据库里一个字段值相等 则把 他合为一条数据
    最近在项目中碰到把对象数组转为键值对,
    js 的数组怎么push一个对象. Js数组的操作push,pop,shift,unshift JavaScrip
    for循环
  • 原文地址:https://www.cnblogs.com/Apocrypha/p/10562586.html
Copyright © 2020-2023  润新知