BZOJ-2002-Bounce弹飞绵羊-分块

描述

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

分析
  • 分块, 维护 i 位置的绵羊经过几次弹出该块(f[]), 以及弹出后落在哪个位置(arv[]). 这样就可以在 n√n 的时间内完成本题.
  • 遇到查询操作, 则每次 ans 加上 f[i], i 转移到 arv[i], 直到 arv[i] ≥ n
  • 遇到修改操作, 则只需维护 该块的 f[] 数组和 arv[] 数组.
  • 维护时不用一个点一个点的计算, 而是从后向前倒推.
  • 我练习了一下对拍和生成数据, 靠对拍发现了错误.

#include 
    
    
     
     
#include 
     
     
      
      
using namespace std;

const int maxn = 200000 + 10;
const int maxb = 500 + 10;

int A[maxn], f[maxn], arv[maxn];
int L[maxb], R[maxb];

int main() {
	int n, m, size, block;
	scanf("%d", &n);
	for(int i = 0; i < n; i++) scanf("%d", &A[i]);
	size = (int)sqrt(n);
	block = n/size + (n%size != 0); //
	for(int b = 0; b < block; b++) {
		L[b] = b*size;
		R[b] = (b+1)*size-1;
	}
	R[block-1] = n-1;
	for(int b = 0; b < block; b++)
		for(int i = R[b]; i >= L[b]; i--) {
			int j = i + A[i];
			if(j > R[b]) f[i] = 1, arv[i] = j;
			else f[i] = f[j] + 1, arv[i] = arv[j];
		}
		
	scanf("%d", &m);
	while(m--) {
		int k, x, b;
		scanf("%d %d", &k, &x);
		b = x/size;
		if(k == 1) {
			int ans = 0;
			while(x < n) ans += f[x], x = arv[x];
			printf("%d\n", ans);
		} else {
			scanf("%d", &A[x]);
			for(int i = R[b]; i >= L[b]; i--) {
				int j = i + A[i];
				if(j > R[b]) f[i] = 1, arv[i] = j;
				else f[i] = f[j] + 1, arv[i] = arv[j];
			}
		}
	}
	return 0;
}
#include 
      
      
       
       
#include 
       
       
        
        
using namespace std;

int main() {
	freopen("bzoj_2002.in", "w", stdout);
//	freopen("bzoj_2002.out", "r", stdin);
	srand(0);
	int n = 100, m = 100;
	printf("%d\n", n);
	
	for(int i = 1; i <= n; i++) printf("%d ", rand() % 9 + 1);
	printf("%d\n", m);
	for(int i = 1; i <= m; i++) {
		int k = rand() % 2 + 1;
		if(k == 1) {
			printf("%d %d\n", k, rand() % n);
		} else {
			printf("%d %d %d\n", k, rand() % n, rand() % 9 + 1);
		}
	}
	return 0;
}
#include 
        
        
          #include 
         
           using namespace std; const int maxn = 200000 + 10; const int maxb = 500 + 10; int A[maxn], f[maxn], arv[maxn]; int L[maxb], R[maxb]; int main() { freopen("bzoj_2002.in", "r", stdin); freopen("bzoj_2002_force.out", "w", stdout); int n, m, size, block; scanf("%d", &n); for(int i = 0; i < n; i++) scanf("%d", &A[i]); scanf("%d", &m); for(int i = 1; i <= m; i++) { int k, x, b; scanf("%d %d", &k, &x); b = x/size; if(k == 1) { int ans = 0; while(x < n) ans++, x += A[x]; printf("%d\n", ans); } else { scanf("%d", &A[x]); } } return 0; } 
          
        
       
       
      
      
     
     
    
    


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值