title: BZOJ2002 弹飞绵羊
date: 2018-07-20 19:39:51
tags: 分块
---
某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞。绵羊想知道当它从第i个装置起步时,被弹几次后会被弹飞。为了使得游戏更有趣,Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。
就不能想一个好点的背景吗?
˼·
很好的想法题,一开始并没有看出来和分块有半毛钱关系。。。
经过WangZY dalao的指点后,知道了要记录本块的绵羊要花多少步跳到下一块,以及跳到下一块的坐标是什么。
深究其原因,我们是牺牲了query的时间来换取了修改的时间,由此避免修改时“牵一发而动全身”,平衡query和修改的时间(这本身也是分块的作用)
#include<bits/stdc++.h> #define M 200005 using namespace std; struct node{ int to;//到哪一个块 int step;//需要多少步 }dp[M]; int n,m,s;//块的大小 int A[M]; //分块,记录每个块会到达下一个哪个块,以及所需的步数 int query(int i){ int res=0,cur=i; while(cur<n){ res+=dp[cur].step; cur=dp[cur].to; } return res; } void up(int i){ if(i+A[i]>=n)dp[i].step=1,dp[i].to=n; else if(i+A[i]>=(i/s+1)*s)dp[i].step=1,dp[i].to=i+A[i]; else dp[i].step=dp[i+A[i]].step+1,dp[i].to=dp[i+A[i]].to; } void update(int x,int y){ A[x]=y; for(int i=min(n-1,(x/s+1)*s);i>=(x/s)*s;i--)up(i); } int main(){ cin>>n; s=sqrt(n); for(int i=0;i<n;i++) scanf("%d",&A[i]); for(int i=n-1;i>=0;i--)up(i); cin>>m; for(int i=1;i<=m;i++){ int f,x,y; scanf("%d",&f); if(f==1){ scanf("%d",&x); printf("%d\n",query(x)); } else { scanf("%d%d",&x,&y); update(x,y); } } return 0; } //想法题
原文:https://www.cnblogs.com/zryabc/p/9348016.html