线段树 transformation——hdu 4578

问题描述:
给定一个数列,数列中所有元素都初始化为0,对其执行多种区间操作
操作1:add修改:对区间[L,R]内的所有数加c
操作2:multi修改:对区间[L,R]内所有数乘以c
操作3:change操作:把区间[L,R]内所有数改为c
操作4:sum操作:对区间中的每个数的p次方求和。1<=p<=3
输入:
有不超过10个测试用例。
对于每个测试用例,第一行包含两个数字n和m,表示有n个整数和m个操作。其中,1 <= n, m <= 100,000。
接下来的m行,每行包含一个操作。操作1到3的格式为:"1 x y c" 或 "2 x y c" 或 "3 x y c"。操作4的格式为:"4 x y p"。
(其中,1 <= x <= y <= n,1 <= c <= 10,000,1 <= p <= 3)
输入以0 0结束。
输出:
对于每个操作4,输出一个整数作为结果,每个结果占一行。答案可能非常大,你只需计算答案除以10007的余数即可。

题目分析:
本题考查对lazy_tag标记的理解,有三种修改操作三种查询操作,意味着需要三种tag标记,我们分别定义为add[],multi[],change[]标记,需要知道的是他们在记录变化的时候,存在什么样的关系。
(1)做change修改时,原有的add和multi标记失效
(2)做multi修改时,如果原有add,则将add改为addmulti
(3)做线段树pushdown操作时,先处理change操作,后处理multi,最后执行add
三种查询操作,求和sum1,平方和sum2,立方和sum3。对于change和multi标记三种查询都很容易计算,对于add标记sum求和容易计算,但平方和与立方和需要推倒:
平方和sum2:
(a+c)2=a2+c
c+2ac,即sum2[new]=sum2[old]+(R-L+1)cc+2sum1[old]c
立方和
(a+c)3=a3+ccc+3c(a**2+ac),即sum3[new]=sum3[old]+(R-L+1)ccc+3c(sum2[old]+sum1[old]c)
注:公式还需要结合操作二

代码:
来自园内大佬

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
using namespace std;
const int MOD = 10007;
const int MAXN = 100010;
struct Node {
	int l, r;
	int sum1, sum2, sum3;
	int lazy1, lazy2, lazy3;
} segTree[MAXN * 3];
void build(int i, int l, int r) {
	segTree[i].l = l;
	segTree[i].r = r;
	segTree[i].sum1 = segTree[i].sum2 = segTree[i].sum3 = 0;
	segTree[i].lazy1 = segTree[i].lazy3 = 0;
	segTree[i].lazy2 = 1;  //乘法标记为1
	int mid = (l + r) / 2;
	if (l == r)return;
	build(i << 1, l, mid);
	build((i << 1) | 1, mid + 1, r);
}
void push_up(int i) {
	if (segTree[i].l == segTree[i].r)
		return;
	segTree[i].sum1 = (segTree[i << 1].sum1 + segTree[(i << 1) | 1].sum1) % MOD;
	segTree[i].sum2 = (segTree[i << 1].sum2 + segTree[(i << 1) | 1].sum2) % MOD;
	segTree[i].sum3 = (segTree[i << 1].sum3 + segTree[(i << 1) | 1].sum3) % MOD;

}

void push_down(int i) {
	if (segTree[i].l == segTree[i].r) return;
	if (segTree[i].lazy3 != 0) {
		segTree[i << 1].lazy3 = segTree[(i << 1) | 1].lazy3 = segTree[i].lazy3;
		//加标记改为0,乘标记改为1即可将标记清除,将原有的标记清除
		segTree[i << 1].lazy1 = segTree[(i << 1) | 1].lazy1 = 0;
		segTree[i << 1].lazy2 = segTree[(i << 1) | 1].lazy2 = 1;
		//左孩子节点更新
		segTree[i << 1].sum1 = (segTree[i << 1].r - segTree[i << 1].l + 1) * segTree[i << 1].lazy3 % MOD;  //c
		segTree[i << 1].sum2 = (segTree[i << 1].r - segTree[i << 1].l + 1) * segTree[i << 1].lazy3 % MOD * segTree[i << 1].lazy3 % MOD;  //c*c
		segTree[i << 1].sum3 = (segTree[i << 1].r - segTree[i << 1].l + 1) * segTree[i << 1].lazy3 % MOD * segTree[i << 1].lazy3 % MOD * segTree[i << 1].lazy3 % MOD; //c*c*c
		//右孩子节点更新
		segTree[(i << 1) | 1].sum1 = (segTree[(i << 1) | 1].r - segTree[(i << 1) | 1].l + 1) * segTree[(i << 1) | 1].lazy3 % MOD;
		segTree[(i << 1) | 1].sum2 = (segTree[(i << 1) | 1].r - segTree[(i << 1) | 1].l + 1) * segTree[(i << 1) | 1].lazy3 % MOD * segTree[(i << 1) | 1].lazy3 % MOD;
		segTree[(i << 1) | 1].sum3 = (segTree[(i << 1) | 1].r - segTree[(i << 1) | 1].l + 1) * segTree[(i << 1) | 1].lazy3 % MOD * segTree[(i << 1) | 1].lazy3 % MOD * segTree[(i << 1) | 1].lazy3 % MOD;
		//标记传递后需要删除
		segTree[i].lazy3 = 0;
	}
	if (segTree[i].lazy1 != 0 || segTree[i].lazy2 != 1) {
		int sum1, sum2, sum3;
		//在做线段树pushdown操作时,先执行change,再执行multi,最后执行add
		
		//更新标记
		segTree[i << 1].lazy1 = (segTree[i].lazy2 * segTree[i << 1].lazy1 % MOD + segTree[i].lazy1) % MOD;
		segTree[i << 1].lazy2 = segTree[i << 1].lazy2 * segTree[i].lazy2 % MOD;

		//更新sum,在做线段树pushdown操作时,先执行change,再执行multi,最后执行add
		sum1 = (segTree[i << 1].sum1 * segTree[i].lazy2 % MOD + (segTree[i << 1].r - segTree[i << 1].l + 1) * segTree[i].lazy1 % MOD) % MOD;
		sum2 = (segTree[i].lazy2 * segTree[i].lazy2 % MOD * segTree[i << 1].sum2 % MOD + 2 * segTree[i].lazy1 * segTree[i].lazy2 % MOD * segTree[i << 1].sum1 % MOD + (segTree[i << 1].r - segTree[i << 1].l + 1) * segTree[i].lazy1 % MOD * segTree[i].lazy1 % MOD) % MOD;
		sum3 = segTree[i].lazy2 * segTree[i].lazy2 % MOD * segTree[i].lazy2 % MOD * segTree[i << 1].sum3 % MOD;
		sum3 = (sum3 + 3 * segTree[i].lazy2 % MOD * segTree[i].lazy2 % MOD * segTree[i].lazy1 % MOD * segTree[i << 1].sum2) % MOD;
		sum3 = (sum3 + 3 * segTree[i].lazy2 % MOD * segTree[i].lazy1 % MOD * segTree[i].lazy1 % MOD * segTree[i << 1].sum1) % MOD;
		sum3 = (sum3 + (segTree[i << 1].r - segTree[i << 1].l + 1) * segTree[i].lazy1 % MOD * segTree[i].lazy1 % MOD * segTree[i].lazy1 % MOD) % MOD;
		segTree[i << 1].sum1 = sum1;
		segTree[i << 1].sum2 = sum2;
		segTree[i << 1].sum3 = sum3;

		segTree[i << 1 | 1].lazy1 = (segTree[i].lazy2 * segTree[i << 1 | 1].lazy1 % MOD + segTree[i].lazy1) % MOD;
		segTree[i << 1 | 1].lazy2 = segTree[i << 1 | 1].lazy2 * segTree[i].lazy2 % MOD;

		sum1 = (segTree[i << 1 | 1].sum1 * segTree[i].lazy2 % MOD + (segTree[i << 1 | 1].r - segTree[i << 1 | 1].l + 1) * segTree[i].lazy1 % MOD) % MOD;
		sum2 = (segTree[i].lazy2 * segTree[i].lazy2 % MOD * segTree[i << 1 | 1].sum2 % MOD + 2 * segTree[i].lazy1 * segTree[i].lazy2 % MOD * segTree[i << 1 | 1].sum1 % MOD + (segTree[i << 1 | 1].r - segTree[i << 1 | 1].l + 1) * segTree[i].lazy1 % MOD * segTree[i].lazy1 % MOD) % MOD;
		sum3 = segTree[i].lazy2 * segTree[i].lazy2 % MOD * segTree[i].lazy2 % MOD * segTree[i << 1 | 1].sum3 % MOD;
		sum3 = (sum3 + 3 * segTree[i].lazy2 % MOD * segTree[i].lazy2 % MOD * segTree[i].lazy1 % MOD * segTree[i << 1 | 1].sum2) % MOD;
		sum3 = (sum3 + 3 * segTree[i].lazy2 % MOD * segTree[i].lazy1 % MOD * segTree[i].lazy1 % MOD * segTree[i << 1 | 1].sum1) % MOD;
		sum3 = (sum3 + (segTree[i << 1 | 1].r - segTree[i << 1 | 1].l + 1) * segTree[i].lazy1 % MOD * segTree[i].lazy1 % MOD * segTree[i].lazy1 % MOD) % MOD;
		segTree[i << 1 | 1].sum1 = sum1;
		segTree[i << 1 | 1].sum2 = sum2;
		segTree[i << 1 | 1].sum3 = sum3;

		//传递后需要清除标记
		segTree[i].lazy1 = 0;
		segTree[i].lazy2 = 1;

	}
}
void update(int i, int l, int r, int type, int c) {
	if (segTree[i].l >= l && segTree[i].r <= r) {
		//根据公式填写即可
		c %= MOD;
		if (type == 1) {
			segTree[i].lazy1 += c;
			segTree[i].lazy1 %= MOD;
			segTree[i].sum3 = (segTree[i].sum3 + 3 * segTree[i].sum2 % MOD * c % MOD + 3 * segTree[i].sum1 % MOD * c % MOD * c % MOD + (segTree[i].r - segTree[i].l + 1) * c % MOD * c % MOD * c % MOD) % MOD;
			segTree[i].sum2 = (segTree[i].sum2 + 2 * segTree[i].sum1 % MOD * c % MOD + (segTree[i].r - segTree[i].l + 1) * c % MOD * c % MOD) % MOD;
			segTree[i].sum1 = (segTree[i].sum1 + (segTree[i].r - segTree[i].l + 1) * c % MOD) % MOD;
		}
		else if (type == 2) {
			segTree[i].lazy1 = segTree[i].lazy1 * c % MOD;
			segTree[i].lazy2 = segTree[i].lazy2 * c % MOD;
			segTree[i].sum1 = segTree[i].sum1 * c % MOD;
			segTree[i].sum2 = segTree[i].sum2 * c % MOD * c % MOD;
			segTree[i].sum3 = segTree[i].sum3 * c % MOD * c % MOD * c % MOD;
		}
		else {
			segTree[i].lazy1 = 0;
			segTree[i].lazy2 = 1;
			segTree[i].lazy3 = c % MOD;
			segTree[i].sum1 = c * (segTree[i].r - segTree[i].l + 1) % MOD;
			segTree[i].sum2 = c * (segTree[i].r - segTree[i].l + 1) % MOD * c % MOD;
			segTree[i].sum3 = c * (segTree[i].r - segTree[i].l + 1) % MOD * c % MOD * c % MOD;
		}
		return;
	}
	push_down(i);
	//二分
	int mid = (segTree[i].l + segTree[i].r) / 2;
	if (l <= mid)update(i << 1, l, r, type, c);
	if (r > mid)update((i << 1) | 1, l, r, type, c);
	push_up(i);
}
int query(int i, int l, int r, int p) {
	if (segTree[i].l >= l && segTree[i].r <= r) {
		if (p == 1)return segTree[i].sum1;
		else if (p == 2)return segTree[i].sum2;
		else return segTree[i].sum3;
	}
	push_down(i);
	int mid = (segTree[i].l + segTree[i].r) / 2;
	int sum = 0;
	if (l <= mid) sum += query(i << 1, l, r, p);
	if (r > mid) sum += query((i << 1) | 1, l, r, p);
	return sum % MOD;
}

int main() {
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	int n, m;
	while (scanf("%d%d", &n, &m) == 2) {
		if (n == 0 && m == 0)break;
		build(1, 1, n);
		int type, x, y, c;
		while (m--) {
			scanf("%d%d%d%d", &type, &x, &y, &c);
			if (type == 4)printf("%d\n", query(1, x, y, c));
			else update(1, x, y, type, c);
		}
	}
	return 0;
}
posted @ 2024-09-10 19:47  小明算法嘎嘎猛  阅读(2)  评论(0编辑  收藏  举报