zoukankan      html  css  js  c++  java
  • luo3372线段树模板的分块做法

    题目大意

    请你维护一个有n个元素的整数序列,要求支持区间查询&区间修改

    对于100%的数据,(1<=n<=10^5)

    分析

    正常做法是线段树维护区间修改、区间查询,今天我要讲的是一种暴力做法:分块

    分块的思想并不复杂,分块把一个长度为n的区间分成num段,操作时如果是整段用标记修改,不是整段的部分暴力修改

    分析时间复杂度:在这题中,每段的标记修改是(O(1))的,最多有num段,整段标记修改所用时间是(O(num))的;不是整段的部分最多有(O(n/num))个,暴力修改所用的时间是(O(n/num))的;所以总时间是(O(num+n/num))

    根据基本不等式,num取(sqrt n)时该式有最小值;所以num取(sqrt n)

    实现

    分块的思想并不复杂,时间复杂度也不玄学,但是实现起来并不方便(可能是我弱)

    分块的修改/查询都分为2部分:

    1. 整块的修改
    2. “零头”的修改

    整块的修改是否简便:add[i] += val;
    “零头”的修改直接修改,同时不要忘了维护所在块的信息:

    a[i] += val;
    sum[id[i]] += val;
    

    修改就愉快地解决了,查询和修改差不多。

    完整代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    
    const int maxn = 100007;
    int n, m, num, id[maxn];
    long long sum[1000], add[1000], a[maxn];
    
    int main(){
    	scanf("%d%d", &n, &m);
    	num = sqrt(n);
    	for (int i = 1; i <= n; ++i){
    		scanf("%lld", &a[i]);
    		id[i] = (i-1) / num;
    		sum[id[i]] += a[i];
    	}
    
    	while (m--){
    		int d; scanf("%d", &d);
    		if (d==1){
    			int x, y, C; scanf("%d%d%d", &x, &y, &C);
    			int Leftid = (x-1) / num + 1;
    			int Rightid = (y-1) / num - 1;
    
    			long long res = 0;
    			for (int i = Leftid; i <= Rightid; ++i)
    				 add[i] += C;
    
    			for (int i = x; i <= Leftid * num; ++i)
    				a[i] += C, sum[id[i]] += C;
    
    			for (int i = (Rightid+1)*num+1; i <= y; ++i)
    				a[i] += C, sum[id[i]] += C;
    		}else{
    			int x, y; scanf("%d%d", &x, &y);
    			int Leftid = (x-1) / num + 1;
    			int Rightid = (y-1) / num - 1;
    
    			if (id[x] == id[y]){
    				long long res = 0;
    				for (int i = x; i <= y; ++i)
    					res += a[i] + add[id[i]];
    				printf("%lld
    ", res);
    				continue;
    			}
    
    			long long res = 0;
    			for (int i = Leftid; i <= Rightid; ++i)
    				res += sum[i] + add[i] * num;
    
    			for (int i = x; i <= Leftid * num; ++i)
    				res += a[i] + add[Leftid-1];
    
    			for (int i = (Rightid+1)*num+1; i <= y; ++i)
    				res += a[i] + add[Rightid+1];
    
    			printf("%lld
    ", res);
    
    		}
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    (BFS 二叉树) leetcode 515. Find Largest Value in Each Tree Row
    (二叉树 BFS) leetcode513. Find Bottom Left Tree Value
    (二叉树 BFS DFS) leetcode 104. Maximum Depth of Binary Tree
    (二叉树 BFS DFS) leetcode 111. Minimum Depth of Binary Tree
    (BFS) leetcode 690. Employee Importance
    (BFS/DFS) leetcode 200. Number of Islands
    (最长回文子串 线性DP) 51nod 1088 最长回文子串
    (链表 importance) leetcode 2. Add Two Numbers
    (链表 set) leetcode 817. Linked List Components
    (链表 双指针) leetcode 142. Linked List Cycle II
  • 原文地址:https://www.cnblogs.com/YJZoier/p/9721774.html
Copyright © 2011-2022 走看看