[HNOI2010]弹飞绵羊 --- 分块

传送门洛谷P3203

题目描述

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

分析

  由题易知这是一个树形结构,而且是一个森林。题目所求为 点到其所在树的根节点之间的边数 + 1;若是加一个总的根节点,那就是一棵树了。
  听说是道LCT的水题(然而并不会),但若是暴力地直接一路向上,统计步数,那么也只能TLE了。对此,可以考虑用分块来优化暴力:将一个块看做整体,记录块内的点到下一个块的步数与位置;至于修改,则将块内的数据相应修改(重构)。

代码

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>

#define IL inline
#define open(s) freopen(s".in", "r", stdin); freopen(s".out", "w", stdout);
#define close fclose(stdin); fclose(stdout);

using namespace std;

IL int read()
{
    int sum = 0, k = 1;
    char c = getchar();
    for(;'0' > c || c > '9'; c = getchar())
    if(c == '-') k = -1;
    for(;'0' <= c && c <= '9'; c = getchar())
        sum = sum * 10 + c - '0';
    return sum * k;
}

int n, m;
int num[200005];
int block;
int id[200005], to[200005], step[200005];

IL int query(int p)
{
    int ans = 0;
    for(; id[p] != -1; p = to[p]) ans += step[p];
    return ans;
}

IL void update(int p)
{
    for(int l = p / block * block, v; p >= l; --p)
    {
        v = p + num[p];
        if(id[p] != id[v])
        {
            step[p] = 1; to[p] = v;
        }else
        {
            step[p] = step[v] + 1; to[p] = to[v];
        }
    }
}

int main()
{
    open("3203")

    n = read(); block = sqrt(n);
    memset(id, -1, sizeof(id));
    for(int i = 0, k = 0; i < n; ++i) 
    {
        num[i] = read();
        id[i] = k;
        if(!((i + 1) % block) || i + 1 == n) ++k;
    }
    for(int i = n - 1, v; i >= 0; --i)
    {
        v = i + num[i];
        if(id[i] != id[v])
        {
            step[i] = 1; to[i] = v;
        }else
        {
            step[i] = step[v] + 1; to[i] = to[v];
        }
    }

    m = read();
    for(int i = 1, x, y; i <= m; ++i)
    {
        x = read(); y = read();
        if(x == 1)
        {
            printf("%d\n", query(y));
        }else
        if(x == 2)
        {
            num[y] = read();
            update(y);
        }
    }
    close
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_27121257/article/details/81057435