分块 (貌似能用LCT做,反正我现在还不会) BZOJ 2002

2002: [Hnoi2010]Bounce 弹飞绵羊

Time Limit: 10 Sec  Memory Limit: 259 MB
Submit: 9844  Solved: 5070
[Submit][Status][Discuss]

Description

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

Input

第一行包含一个整数n,表示地上有n个装置,装置的编号从0到n-1,接下来一行有n个正整数,依次为那n个装置的初始弹力系数。第三行有一个正整数m,接下来m行每行至少有两个数i、j,若i=1,你要输出从j出发被弹几次后被弹飞,若i=2则还会再输入一个正整数k,表示第j个弹力装置的系数被修改成k。对于20%的数据n,m<=10000,对于100%的数据n<=200000,m<=100000

Output

对于每个i=1的情况,你都要输出一个需要的步数,占一行。

Sample Input

4

1 2 1 1

3

1 1

2 1 1

1 1

Sample Output

2

3

HINT

Source

思路:感觉这个如果说用分块的话感觉是基础题?

总体思路就是分成sqrt(n)块,然后每次都对这个块内进行更新, need表示每次走的步数,我们就只要for(j = r[i]; j >= l[i]; j--) 来逆序迭代更新就好了。

//看看会不会爆int!数组会不会少了一维!
//取物问题一定要小心先手胜利的条件
#include <bits/stdc++.h>
using namespace std;
#pragma comment(linker,"/STACK:102400000,102400000")
#define LL long long
#define ALL(a) a.begin(), a.end()
#define pb push_back
#define mk make_pair
#define fi first
#define se second
#define haha printf("haha\n")
const int maxn = 200000 * 2;
int n, m;
int step[maxn];
int l[maxn], r[maxn], belong[maxn], block, num;
int to[maxn], need[maxn];

void build(){
    block = sqrt(n); num = n / block;
    if (n % block) num++;
    for (int i = 1; i <= num; i++){
        l[i] = (i - 1) * block + 1, r[i] = i * block;
    }
    for (int i = 1; i <= n; i++)
        belong[i] = (i - 1) / block + 1;
}

void update(int be){
    for (int i = l[be]; i <= r[be]; i++)
        to[i] = -1, need[i] = 0;
    for (int i = r[be]; i >= l[be]; i--){
        int nxtpos = i + step[i];
        if (nxtpos > n) nxtpos = n + 1;
        if (belong[nxtpos] != be){//如果只走一步,且两个不是同一个块
            to[i] = nxtpos; need[i] = 1;
        }
        else {//同一个块
            need[i] = 1;
            need[i] += need[nxtpos];
            to[i] = to[nxtpos];
        }
    }
}

void query(int pos){
    int cnt = 0;
    while (pos <= n){
        cnt += need[pos];
        pos = to[pos];
    }
    printf("%d\n", cnt);
}

int main(){
    cin >> n;
    for (int i = 1; i <= n; i++){
        scanf("%d", step + i);
    }
    build();
    memset(to, -1, sizeof(to));
    for (int i = 1; i <= num; i++){
        update(i);
    }
/*
    for (int i = 1; i <= n; i++){
        printf("to[%d] = %d need[%d] = %d\n", i, to[i], i, need[i]);
    }
*/
    cin >> m;
    for (int i = 1; i <= m; i++){
        int a, b, c;
        scanf("%d%d", &a, &b); b++;
        if (a == 2){
            scanf("%d", &c);
            step[b] = c;
            update(belong[b]);
        }
        else {
            query(b);
        }
    }
    return 0;
}

关键:分块的魅力在于每次不需要将序列全部更新,而是只需要更新其中的片段

时间: 2024-08-13 22:20:30

分块 (貌似能用LCT做,反正我现在还不会) BZOJ 2002的相关文章

国产动漫想活,做点比盗版还好的玩具先

在很多人眼里,动漫的图书.影视方面的侵权危害较大,但实际上,几乎被盗版动漫周边产品包围的市场,才直接影响到了整个动漫产业的健康发展,也使得国内动漫产业自身缺乏有效的造血机制,无法通过"粉丝经济"获得效益. 文/张书乐 盗版动漫衍生品的现象在国内并不少见,例如市场上随处可见的喜羊羊.灰太狼.虹猫蓝兔等国产动漫形象的毛绒玩具.童鞋等,这些大多是没有经过任何授权的盗版产品.而国产动漫在经过十多年的市场化运作后,似乎依然没有多少起色.为此,笔者和<法制日报>记者廉颖婷有了一番交谈,

你连自律都做不到,还奢谈什么自由?

本文由作者 菜刀少爷 授权罗辑思维发布,选自微信公众号“菜刀少爷”. 1 牛人都是狠角色 据说史蒂夫·乔布斯年轻时每天凌晨四点起床,九点前把一天工作做完.乔帮主说:自由从何而来?从自信来,而自信则是从自律来. 自律是对自我的控制,自信是对事情的控制.先学会克制自己,用严格的日程表控制生活,才能在这种自律中不断磨练出自信. 都是成年人,连最基本的行为控制都做不到,还谈什么自信?又奢谈什么自由? 前华人首富李嘉诚以勤奋自律著称.他的作息时间非常有名: 不论几点睡觉,在清晨5点59分闹铃响后起床:随后

做个笨鸟还能先飞

其实聪明和笨都是相对而言的,每个人的标准不同.在职场上,也许你不用那么聪明,试着把自己当成一个笨人吧,因为你始终要记住,笨鸟是能都先飞的 !(本文来自e良师益友网) 有些职场中公认的聪明人,只是聪明浮于表面,让大家都看出来而已.让所有人都见识自己的聪明,在职场上并没有太大的好处.因为对老板而言,聪明不代表有能力.对上司而言,聪明代表着难管.而对同事而言,聪明代表着压力.你把一个有害无利的东西表达出来,只会给自己带来麻烦,而这除了能满足下自己的虚荣心之外,实在毫无好处. 1.笨蛋比聪明人更聪明 看

BZOJ 2002 LCT板子题

思路: LCT啊... (分块也行) 不过YOUSIKI出了一道"弹飞大爷" 就不能用分块水过去了 //By SiriusRen #include <cstdio> #include <algorithm> using namespace std; const int N=200050; int fa[N],ch[N][2],rev[N],size[N],n,op,q[N],top,a[N],m,xx,yy; bool isroot(int x){return

值得一做》关于双标记线段树两三事BZOJ 1798 (NORMAL-)

这是一道双标记线段树的题,很让人很好的预习/学习/复习线段树,我不知道它能让别人学习什么,反正让我对线段树的了解更加深刻. 题目没什么好讲的,程序也没什么好讲的,所以也没有什么题解,但是值得一做 给出题目&代码 Description 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列中的一段数的和,由于答案可能很大,你只需

BZOJ 2002 HNOI2010 弹飞绵羊 分块

题目大意及LCT版本题解:见 http://blog.csdn.net/popoqqq/article/details/38849471 今天手滑用分块又重写了一遍这道题0.0 分块就是短啊 将弹簧分为√n块 对于每个弹簧 我们记录一下从这个弹簧出发直到弹到块外为止的弹跳次数及落点 查询沿着落点弹到出去为止 修改从块开始到这个点为止修改一遍 这样修改和查询都是O(√n)的 #include<cmath> #include<cstdio> #include<cstring>

bzoj 2002 : [Hnoi2010]Bounce 弹飞绵羊 (LCT)

链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2002 题面: 2002: [Hnoi2010]Bounce 弹飞绵羊 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 15763  Solved: 8080[Submit][Status][Discuss] Description 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开

BZOJ 2002 Bounce 弹飞绵羊(分块|暴力|)(困难)

Bounce 弹飞绵羊 Time Limit:10000MS     Memory Limit:265216KB     64bit IO Format:%lld & %llu Submit Status Practice HYSBZ 2002 Description 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后

BZOJ 2002: [Hnoi2010]Bounce 弹飞绵羊( LCT )

LCT... ---------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #define rep( i , n ) for( int i = 0 ; i < n ; ++i ) #define clr( x , c ) memset( x