• 奇偶线段树(区间更新)


    题目链接: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; }



  • 相关阅读:
    RESTful API 设计指南
    SpringBoot系列
    spring boot RESTFul
    mark--唧唧歪歪--2021.2.8
    接口踩坑:Status (blocked:other)
    获取layer.open弹出层的返回值
    VUE_CLI4.5 VUE+Cesium
    Android Studio AVD 模拟器 自带虚拟机 联网 连接网络
    一文搞懂TCP与UDP的区别
    springboot打包成war,部署到tomcat无法访问的问题
  • 原文地址:https://www.cnblogs.com/cynchanpin/p/6962695.html
Copyright © 2020-2023  润新知