zoukankan      html  css  js  c++  java
  • [bzoj2002][Hnoi2010]Bounce弹飞绵羊——分块

    Brief description

    某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞。绵羊想知道当它从第i个装置起步时,被弹几次后会被弹飞。为了使得游戏更有趣,Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。

    Algorithm design

    因为太弱不会用lct,所以我们使用分块做Orz
    考察暴力解法:
    第一种暴力做法就是修改的时候直接(Theta(1))修改,查询的时候要(Theta(n))查询。
    第二种暴力做法就是修改的时候把所有的答案重新递推出来,复杂度(Theta(n)),查询的时候就可以(Theta(1))查询了。
    我们考虑分块把两种方法结合起来。设分块的大小为(h(n))
    首先我们预处理出来每个点跳出当前块需要多少步,并且跳出之后会落在哪里。
    考虑修改。对于每个点,如果我们修改,会导致所有可以到达它的点的答案变化。我们只修改块内的答案,不难证明这样做是可行的。复杂度(Theta(h(n)))
    考虑查询。根据预处理信息,我们可以方便的查询。

    Code

    #include <cmath>
    #include <cstdio>
    #include <cstring>
    const int maxn = 200100;
    const int inf = 0x3f3f3f;
    int n, m, f[maxn], g[maxn], h[maxn], k[maxn], block;
    int id(int x) {
      if (block != 0)
        return (x - 1) / block + 1;
      return 1;
    }
    int main(int argc, char const *argv[]) {
    #ifndef ONLINE_JUDGE
      freopen("input", "r", stdin);
    #endif
      scanf("%d", &n);
      block = (int)sqrt(n);
      memset(f, -1, sizeof(f));
      for (int i = 1; i <= n; i++) {
        int x;
        scanf("%d", &x);
        f[i] = i + x;
        if (f[i] > n)
          f[i] = -1;
        k[i] = -1;
        h[i] = -1;
        g[i] = inf;
      }
      k[n + 1] = 0;
      for (int i = n; i >= 1; i--) {
        if (f[i] != -1) {
          k[i] = k[f[i]] + 1;
          if (id(i) == id(f[i])) {
            g[i] = g[f[i]] + 1;
            h[i] = h[f[i]];
          } else {
            g[i] = 1;
            h[i] = f[i];
          }
        } else {
          k[i] = 1;
          g[i] = 1;
          h[i] = -1;
        }
      }
      scanf("%d", &m);
      while (m--) {
        int opt;
        scanf("%d", &opt);
        if (opt == 1) {
          if (block == 0) {
            printf("0
    ");
            continue;
          }
          int x;
          scanf("%d", &x);
          x++;
          int ans = 1;
          while (f[x] != -1) {
            if (h[x] != -1) {
              ans += g[x];
              x = h[x];
            } else {
              x = f[x];
              ans++;
            }
          }
          printf("%d
    ", ans);
        }
        if (opt == 2) {
          if (block == 0)
            continue;
          int x, y;
          scanf("%d %d", &x, &y);
          x++;
          f[x] = x + y;
          k[x] = k[y] + 1;
          if (f[x] > n)
            f[x] = -1;
          if (id(y) == id(x))
            g[x] = g[y] + 1, h[x] = h[y];
          else
            g[x] = y, h[x] = 1;
          for (int i = x; id(i) == id(x) && i; i--) {
            if (f[i] != -1) {
              k[i] = k[f[i]] + 1;
              if (id(i) == id(f[i])) {
                g[i] = g[f[i]] + 1;
                h[i] = h[f[i]];
              } else {
                g[i] = 1;
                h[i] = f[i];
              }
            } else {
              k[i] = 1;
              g[i] = 1;
              h[i] = -1;
            }
          }
        }
      }
      return 0;
    }
    
  • 相关阅读:
    MySQL行(记录)的详细操作一 介绍 二 插入数据INSERT 三 更新数据UPDATE 四 删除数据DELETE 五 查询数据SELECT 六 权限管理
    {MySQL完整性约束}一 介绍 二 not null与default 三 unique 四 primary key 五 auto_increment 六 foreign key 七 作业
    { MySQL基础数据类型}一 介绍 二 数值类型 三 日期类型 四 字符串类型 五 枚举类型与集合类型
    MySQL的sql_mode模式说明及设置
    {MySQL存储引擎介绍}一 存储引擎解释 二 MySQL存储引擎分类 三 不同存储引擎的使用
    {MySQL的库、表的详细操作}一 库操作 二 表操作 三 行操作
    小爬爬2.数据解析
    小爬爬2:fiddler安装和了解fiddler
    小爬爬2.回顾
    小爬爬1.requests基础操作
  • 原文地址:https://www.cnblogs.com/gengchen/p/6523890.html
Copyright © 2011-2022 走看看