zoukankan      html  css  js  c++  java
  • 数列分块解决区间更新+区间最值问题

    题目大意:

    给定一个大小为 \(n\) 的数列 \(a_1, a_2, \ldots, a_n\),你需要对这个数列进行 \(m\) 次操作,操作包含如下两种类型:

    • 1 x y z :将区间 \([x,y]\) 范围内的所有元素更新为 \(z\)(即:\(a_x, a_{x+1}, \ldots, a_y\) 的值都将变为 \(z\));
    • 2 x y :查询区间 \([x,y]\) 范围内所有元素的最大值。

    对于 \(100\%\) 的数据,\(1 \le n,m \le 2 \times 10^5, op \in [1,2],1 \le x \le y \le n, 1 \le z,a_i \le 10^9\)

    解题思路:

    • tag[i] 维护分块 \(i\) 在整体更新的情况下的数值;
    • sum[i] 维护分块 \(i\) 在任意时刻的最大值。

    示例程序:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 200020;
    int n, blo, m, a[maxn], bl[maxn], tag[505], mx[505], op, x, y, z;	
    // blo=sqrt(n)表示每一个分块的大小  block分块 
    // bl[i] 表示第i个点所属的分块编号 
    // 区间更新[l,r]全部更新为z
    // tag[x]表示第x个分块在全部一样(整体更新)的情况下的数值
    // mx[x]表示第x个分块的最大值 
    
    // 将tag[x]的值全部更新到属于第x个分块的所有元素 
    void recover(int x) {
    	// [(x-1)*blo+1, min(x*blo, n)]
    	if (tag[x]) {
    		for (int i = (x-1)*blo+1; i <= min(x*blo, n); i ++)
    			a[i] = tag[x];
    		mx[x] = tag[x]; // 何时何地mx[x]维护的都是区间的最大值 
    		tag[x] = 0;
    	}
    }
    
    // (重新)计算mx[x]的值 
    void calmx(int x) {
    	mx[x] = 0;
    	for (int i = (x-1)*blo+1; i <= min(x*blo, n); i ++)
    		mx[x] = max(mx[x], a[i]);
    }
    
    void update(int l, int r, int z)
    {
    	// 1. 处理a[l]所在的分块(单独处理) 
    	recover(bl[l]);
    	for (int i = l; i <= min(bl[l]*blo, r); i ++)
    		a[i] = z;
    	calmx(bl[l]);
    	// 2. 处理a[r]所在的分块(单独处理) 
    	if (bl[l] != bl[r]) {
    		recover(bl[r]);
    		for (int i = (bl[r]-1)*blo+1; i <= r; i ++)
    			a[i] = z;
    		calmx(bl[r]);
    	}
    	// 3. 处理 bl[l]+1 到 bl[r]-1 这些中间的完整的分块
    	for (int i = bl[l]+1; i < bl[r]; i ++)
    		mx[i] = tag[i] = z;
    } 
    
    // 查询区间[l,r]的最大值 
    int query(int l, int r)
    {
    	int res = 0;
    	// 1. 处理a[l]所在的分块(单独处理) 
    	recover(bl[l]);
    	for (int i = l; i <= min(bl[l]*blo, r); i ++)
    		res = max(res, a[i]);
    	// 2. 处理a[r]所在的分块(单独处理) 
    	if (bl[l] != bl[r]) {
    		recover(bl[r]);
    		for (int i = (bl[r]-1)*blo+1; i <= r; i ++)
    			res = max(res, a[i]);
    	}
    	// 3. 处理 bl[l]+1 到 bl[r]-1 这些中间的完整的分块
    	for (int i = bl[l]+1; i < bl[r]; i ++)
    		res = max(res, mx[i]);
    	return res;
    } 
    
    int main()
    {
    	scanf("%d%d", &n, &m);
    	blo = sqrt(n);
    	for (int i = 1; i <= n; i ++)
    	{
    		scanf("%d", a+i);
    		bl[i] = (i - 1) / blo + 1;
    		mx[bl[i]] = max(mx[bl[i]], a[i]);
    	}
    	while (m --) {
    		scanf("%d%d%d", &op, &x, &y);
    		if (op == 1) {	// 区间[x,y]全部更新为z 
    			scanf("%d", &z);
    			update(x, y, z);
    		}
    		else {	// 查询区间[x,y]的最大值 
    			printf("%d\n", query(x, y));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    svn不提交.net项目中的bin
    java 与C# 时间格式 交互
    生成菜单序列号
    ashx 方法模板
    webservice使用方法
    如何配置IIS服务器?
    zepto.fullpage
    模拟单选框
    star score
    Hover show tips
  • 原文地址:https://www.cnblogs.com/quanjun/p/15608824.html
Copyright © 2011-2022 走看看