zoukankan      html  css  js  c++  java
  • 奇偶线段树(区间更新)

    题目链接:http://ccnu.acmclub.com/index.php?app=problem_title&id=613&problem_id=23875


    题意:给你一个长度为n的数组(下标从1開始)。进行例如以下操作。

    (1)1 x y v :表示将下标=(x,x+2,x+4。x+6,.......而且<=y)的元素所有+v;

    (2)2 x y :查询[x,y]闭区间的元素和。


    思路:构造2棵线段树。将区间[1,3,...,2k - 1]改为[1。2。...,k],用一棵线段树统计这个区间内的和。

    将区间[2,4。...。2k]改为[1,2。...。k],用一棵线段树统计这个区间内的和。

    剩下为普通的区间更新就可以。


    代码:

    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <math.h>
    #include <algorithm>
    #include <string>
    
    using namespace std;
    
    #define lson l, m, rt << 1
    #define rson m + 1, r, rt << 1 | 1
    #define ceil(x, y) (((x) + (y) - 1) / (y))
    
    const int N = 1e5 + 10;
    const int INF = 0x7f7f7f7f;
    
    struct Node {
    	long long sum;
    	long long add;
    };
    Node node[3][N << 2];//0 偶线段树 1 奇线段树
    long long a[N];
    
    void pushup(int op, int rt) {
    	node[op][rt].sum = node[op][rt << 1].sum + node[op][rt << 1 | 1].sum;
    }
    
    void pushdown(int op, int rt, int len) {
    	int lenl = (len - (len >> 1));
    	int lenr = (len >> 1);
    	if (node[op][rt].add) {
    		node[op][rt << 1].sum += 1LL * lenl * node[op][rt].add;
    		node[op][rt << 1 | 1].sum += 1LL * lenr * node[op][rt].add;
    		node[op][rt << 1].add += node[op][rt].add;
    		node[op][rt << 1 | 1].add += node[op][rt].add;
    		node[op][rt].add = 0;
    	}
    }
    
    void build(int op, int l, int r, int rt) {
    	node[op][rt].add = 0;
    	if (l == r) {
    		if (op)
    			node[op][rt].sum = a[2 * l - 1];
    		else
    			node[op][rt].sum = a[2 * l];
    		return ;
    	}
    	int m = (l + r) >> 1;
    	build(op, lson);
    	build(op, rson);
    	pushup(op, rt);
    }
    
    void update(int op, int L, int R, long long c, int l, int r, int rt) {
    	if (L <= l && r <= R) {
    		node[op][rt].sum += 1LL * (r - l + 1) * c;
    		node[op][rt].add += c;
    		return ;
    	}
    	pushdown(op, rt, r - l + 1);
    	int m = (l + r) >> 1;
    	if (L <= m)
    		update(op, L, R, c, lson);
    	if (R > m)
    		update(op, L, R, c, rson);
    	pushup(op, rt);
    }
    
    long long query(int op, int L, int R, int l, int r, int rt) {
    	if (L <= l && r <= R) {
    		return node[op][rt].sum;
    	}
    	pushdown(op, rt, r - l + 1);
    	int m = (l + r) >> 1;
    	long long ql = 0, qr = 0;
    	if (L <= m)
    		ql = query(op, L, R, lson);
    	if (R > m)
    		qr = query(op, L, R, rson);
    	pushup(op, rt);
    	return ql + qr;
    }
    
    int main() {	
    	int t_case;
    	scanf("%d", &t_case);
    	for (int i_case = 1; i_case <= t_case; i_case++) {
    		int n, m;
    		int no, ne;
    		bool flag = false;
    		scanf("%d%d", &n, &m);
    		for (int i = 1; i <= n; i++) 
    			scanf("%lld", &a[i]);
    		no = ceil(n, 2);
    		ne = n - no;
    		build(1, 1, no, 1);
    		if (ne) {//是否须要建偶线段树
    			build(0, 1, ne, 1);
    			flag = true;
    		}
    		for (int i_q = 1; i_q <= m; i_q++) {
    			int op, l, r;
    			scanf("%d%d%d", &op, &l, &r);
    			if (op == 1) {
    				long long v;
    				scanf("%lld", &v);
    				if ((l + r) & 1)
    					r--;
    				if (l & 1)
    					update(1, ceil(l, 2), ceil(r, 2), v, 1, no, 1);
    				else 
    					update(0, ceil(l, 2), ceil(r, 2), v, 1, ne, 1);
    			}
    			else {
    				int Ol = ceil((l & 1 ? l : l + 1), 2);
    				int Or = ceil((r & 1 ? r : r - 1), 2);
    				int El = ceil((l & 1 ? l + 1 : l), 2);
    				int Er = ceil((r & 1 ?

    r - 1 : r), 2); long long qo = 0, qe = 0; if (Ol <= Or)//区间合法 qo = query(1, Ol, Or, 1, no, 1); if (flag && El <= Er) qe = query(0, El, Er, 1, ne, 1); printf("%lld ", qo + qe); } } } return 0; }



  • 相关阅读:
    DM6437 dsp系列之启动过程全析(2)—AIS文件解析
    DreamWeaver文件保存时,提示"发生共享违例"问题的解决方法
    再谈cacheAsBitmap
    as3 updateAfterEvent的作用
    导致flash屏幕重绘的几种方式及避免重绘的方法
    盒子模型&position定位
    [工作问题总结]MyEclipse 打开项目
    三周的苦逼学习,这点文字只为沧海之一粟
    偷个空,写个博客——各种沟通各种纠结
    Arbitrage HDU
  • 原文地址:https://www.cnblogs.com/cynchanpin/p/6962695.html
Copyright © 2011-2022 走看看