zoukankan      html  css  js  c++  java
  • 洛谷 P4868 【Preprefix sum】

    线段树题解qwq


    这道题其实把式子一推就行了。因为要求前缀和的前缀和,那为什么我们不维护前缀和,然后求前缀和呢?对于维护前缀和,我们只需要两种操作:区间修改,区间查询。

    区间查询是查询前缀和的前缀和嘛,这个是区间操作没问题,但为什么是区间修改?题目不是单点修改吗?我们先推一下式子:

    原数列:

    (x_1,x_2,x_3,x_4,x_5)

    前缀和:

    (x_1,x_1+x_2,x_1+x_2+x_3,x_1+x_2+x_3+x_4,x_1+x_2+x_3+x_4+x_5)

    可以发现,我们如果修改了(x_1),对于后面的每一个数都变化了,继续推,发现每一个(x)的变化都会影响到后面的每一个数,所以当修改(x_i)时,我们要修改的范围其实是(i-n),那么线段树模板就来了。

    诶等等,他是修改,而不是加减,这里坑就来了,我们要先拿一个数组存储一下每一次修改后的序列,这样对于下一次修改的时候,我们就可以直接比较一下修改数和原数,这样就可以把修改数转化为加减了。

    #include <bits/stdc++.h>
    using namespace std;
    #define ls 2 * p
    #define rs 2 * p + 1
    long long n , m , last;	//太懒了直接全部long long 
    long long sum[4000010] , tag[4000010] , a[1000010];
    void pushdown(long long l , long long r , long long p){	//下传标记 
    	if(l == r || tag[p] == 0) return;
    	long long mid = (l + r) / 2;
    	sum[ls] += (mid - l + 1) * tag[p];
    	sum[rs] += (r - mid) * tag[p];
    	tag[ls] += tag[p];
    	tag[rs] += tag[p];
    	tag[p] = 0;
    }
    void add(long long l , long long r , long long s , long long t , long long k , long long p){	//区间加 
    	if(l >= s && r <= t){
    		sum[p] += (r - l + 1) * k;
    		tag[p] += k;
    		return;
    	}
    	pushdown(l , r , p);
    	long long mid = (l + r) / 2;
    	if(mid >= s) add(l , mid , s , t , k , ls);
    	if(mid < t) add(mid + 1 , r , s , t , k , rs);
    	sum[p] = sum[ls] + sum[rs];
    }
    long long query(long long l , long long r , long long s , long long t , long long p){	//区间求和 
    	if(l >= s && r <= t) return sum[p];
    	pushdown(l , r , p);
    	long long mid = (l + r) / 2 , ans = 0;
    	if(mid >= s) ans += query(l , mid , s , t , ls);
    	if(mid < t) ans += query(mid + 1 , r , s , t , rs);
    	return ans;
    }
    int main(){
    	cin >> n >> m;
    	for(long long i = 1; i <= n; i++){
    		cin >> a[i];
    		add(1 , n , i , i , a[i] + last , 1);	//维护前缀和 
    		last += a[i];
    	} 
    	while(m--){
    		string st;
    		long long x , k;
    		cin >> st;
    		if(st[0] == 'Q'){
    			cin >> x;
    			cout << query(1 , n , 1 , x , 1) << endl;
    		}else{
    			cin >> x >> k;
    			add(1 , n , x , n , k - a[x] , 1);	//转化为区间加减 
    			a[x] = k;	//存一下修改后序列 
    		}
    	}
        return 0;
    }
    
  • 相关阅读:
    【代码笔记】iOS-判断textField里面是否有空
    【代码笔记】iOS-判断字符串是否为空
    【代码笔记】iOS-判断中英文混合的字符长度的两种方法
    【代码笔记】iOS-判断有无网络
    【代码笔记】iOS-判断是否是iPhone5
    iOS动画-扩散波纹效果
    (转)对称加密与非对称加密,以及RSA的原理
    (转)iOS GPUImage研究总结
    @inerface的11条规范写法
    Python开发之路
  • 原文地址:https://www.cnblogs.com/bzzs/p/13451260.html
Copyright © 2011-2022 走看看