[HDU - 4578]Transformation(线段树+多重懒标记)

这篇具有很好参考价值的文章主要介绍了[HDU - 4578]Transformation(线段树+多重懒标记)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、问题

[HDU - 4578]Transformation(线段树+多重懒标记)

二、分析

这道题涉及到了区间操作,所以我们用线段树算法。同时,这道题里面有区间修改的操作,所以我们还要用到懒标记。

这里一共有三种区间的操作,分别是:加、乘、赋值。这三种操作无法用一个懒标记来统一,所以我们需要使用三个懒标记来完成这道题。

这道题的查询操作也分为三种,一次方的和、二次方的和、三次方的和。

所以我们需要去维护三种 s u m sum sum

1、节点定义

/*
tag_1 --> 加法
tag_2 --> 乘法
tag_3 --> 赋值
*/
struct Node
{
	int l, r;
	int sum1, sum2, sum3;
	int tag_1, tag_2, tag_3;
}tre[N * 4];

2、pushup

p u s h u p pushup pushup函数就是利用子节点来更新父节点,这个操作比较简单,直接合并三种和即可。

//lson 是左儿子, rson是右儿子
void pushup(int u)
{
	tre[u].sum1 = (tre[lson].sum1 + tre[rson].sum1) % mod;
	tre[u].sum2 = (tre[lson].sum2 + tre[rson].sum2) % mod;
	tre[u].sum3 = (tre[lson].sum3 + tre[rson].sum3) % mod;
}

3、pushdown

p u s h d o w n pushdown pushdown操作是将三种懒标记下传的操作。这里需要注意两个问题:
1、每种标记如何下传?
2、三种标记之间下传的优先级问题。

(1)每种标记如何下传?

赋值

赋值公式如下图所示:
[HDU - 4578]Transformation(线段树+多重懒标记)
l e n = r − l + 1 len = r - l + 1 len=rl+1
另外需要注意在计算过程中进行取模。

乘法

如下图所示:
[HDU - 4578]Transformation(线段树+多重懒标记)
提取公因式即可。

加法

加法是最难处理的,分类讨论一下。
先说一次方。
[HDU - 4578]Transformation(线段树+多重懒标记)
再说二次方
[HDU - 4578]Transformation(线段树+多重懒标记)
最后说三次方
[HDU - 4578]Transformation(线段树+多重懒标记)

(2)三种标记下传的优先级问题

对于某一个区间而言,三种操作可能同时出现。当出现赋值操作的时候,说明在此操作之前出现的加、乘都没有用了,因为都被当前的赋值操作覆盖掉了。所以我们最先考虑的是赋值操作。

如果该区间没有赋值操作,我们考虑的就是乘法操作,乘法出现的时候,说明在此次操作之前的加法操作的数值p也同样需要翻对应的倍数。

最后我们考虑加法。

综合上述讨论,我们可以写出下面的函数实现:

另外我们需要注意,在下传的过程中,我们要将左右区间的标记转化到对应的数值上。

void pushdown(int u)
{
	auto &root = tre[u], &left = tre[lson], &right = tre[rson];
	if(root.tag_3)
	{
		int c = root.tag_3;
		int len1 = (left.r - left.l + 1);
		left.sum1 = len1 * c % mod;
		left.sum2 = len1 * c * c % mod;
		left.sum3 = len1 * c % mod * c % mod * c % mod;
		
		int len2 = (right.r - right.l + 1);
		right.sum1 = len2 * c % mod;
		right.sum2 = len2 * c * c % mod;
		right.sum3 = len2 * c * c * c % mod;
		
		left.tag_3 = right.tag_3 = c;
		left.tag_1 = right.tag_1 = 0;
		left.tag_2 = right.tag_2 = 1;
		root.tag_3 = 0;
	}
	if(root.tag_2 != 1)
	{
		int c = root.tag_2;
		left.sum1 = left.sum1 * c % mod;
		left.sum2 = left.sum2 * c * c % mod;
		left.sum3 = left.sum3 * c * c * c % mod;

		right.sum1 = right.sum1 * c % mod;
		right.sum2 = right.sum2 * c * c % mod;
		right.sum3 = right.sum3 * c * c * c % mod;		
		
		right.tag_2 = c * right.tag_2 % mod;
		left.tag_2 = c * left.tag_2 % mod;

		right.tag_1 = c * right.tag_1 % mod;
		left.tag_1 = c * left.tag_1 % mod;

		root.tag_2 = 1; 
	}

	if(root.tag_1)
	{
		int c = root.tag_1;

		int s1 = left.sum1;
		int s2 = left.sum2;
		
		int len1 = left.r - left.l + 1;
		left.sum1 = (left.sum1 + len1 * c) % mod;
		left.sum2 = (left.sum2 + 2 * s1 * c + len1 * c * c) % mod;
		left.sum3 = (left.sum3 + 3 * c * s2 + 3 * s1 * c * c + len1 * c * c * c) % mod;
		
		s1 = right.sum1;
		s2 = right.sum2;
		int len2 = right.r - right.l + 1;
		right.sum1 = (right.sum1 + len2 * c) % mod;
		right.sum2 = (right.sum2 + 2 * s1 * c + len2 * c * c % mod) % mod;
		right.sum3 = (right.sum3 + 3 * c * s2 % mod + 3 * s1 * c * c % mod + len2 * c % mod * c % mod * c % mod ) % mod;
		
		left.tag_1 = (c + left.tag_1) % mod;
		right.tag_1 = (c + right.tag_1) % mod;
		root.tag_1 = 0;
	}
}

以上就是这道题所有的难点,剩下的函数操作就比较常规了。大家直接看代码实现即可。文章来源地址https://www.toymoban.com/news/detail-424327.html

三、代码

#include<bits/stdc++.h>
#define endl '\n'
#define INF 0x3f3f3f3f
#define lson u << 1
#define rson u << 1 | 1
#define int long long
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N = 1e5 + 10;
const int mod = 1e4 + 7;
int n, m;
struct Node
{
	int l, r;
	int sum1, sum2, sum3;
	int tag_1, tag_2, tag_3;
}tre[N * 4];

void pushup(int u)
{
	tre[u].sum1 = (tre[lson].sum1 + tre[rson].sum1) % mod;
	tre[u].sum2 = (tre[lson].sum2 + tre[rson].sum2) % mod;
	tre[u].sum3 = (tre[lson].sum3 + tre[rson].sum3) % mod;
}

void pushdown(int u)
{
	auto &root = tre[u], &left = tre[lson], &right = tre[rson];
	if(root.tag_3)
	{
		int c = root.tag_3;
		int len1 = (left.r - left.l + 1);
		left.sum1 = len1 * c % mod;
		left.sum2 = len1 * c * c % mod;
		left.sum3 = len1 * c % mod * c % mod * c % mod;
		
		int len2 = (right.r - right.l + 1);
		right.sum1 = len2 * c % mod;
		right.sum2 = len2 * c * c % mod;
		right.sum3 = len2 * c * c * c % mod;
		
		left.tag_3 = right.tag_3 = c;
		left.tag_1 = right.tag_1 = 0;
		left.tag_2 = right.tag_2 = 1;
		root.tag_3 = 0;
	}
	if(root.tag_2 != 1)
	{
		int c = root.tag_2;
		left.sum1 = left.sum1 * c % mod;
		left.sum2 = left.sum2 * c * c % mod;
		left.sum3 = left.sum3 * c * c * c % mod;

		right.sum1 = right.sum1 * c % mod;
		right.sum2 = right.sum2 * c * c % mod;
		right.sum3 = right.sum3 * c * c * c % mod;		
		
		right.tag_2 = c * right.tag_2 % mod;
		left.tag_2 = c * left.tag_2 % mod;

		right.tag_1 = c * right.tag_1 % mod;
		left.tag_1 = c * left.tag_1 % mod;

		root.tag_2 = 1; 
	}

	if(root.tag_1)
	{
		int c = root.tag_1;

		int s1 = left.sum1;
		int s2 = left.sum2;
		
		int len1 = left.r - left.l + 1;
		left.sum1 = (left.sum1 + len1 * c) % mod;
		left.sum2 = (left.sum2 + 2 * s1 * c + len1 * c * c) % mod;
		left.sum3 = (left.sum3 + 3 * c * s2 + 3 * s1 * c * c + len1 * c * c * c) % mod;
		
		s1 = right.sum1;
		s2 = right.sum2;
		int len2 = right.r - right.l + 1;
		right.sum1 = (right.sum1 + len2 * c) % mod;
		right.sum2 = (right.sum2 + 2 * s1 * c + len2 * c * c % mod) % mod;
		right.sum3 = (right.sum3 + 3 * c * s2 % mod + 3 * s1 * c * c % mod + len2 * c % mod * c % mod * c % mod ) % mod;
		
		left.tag_1 = (c + left.tag_1) % mod;
		right.tag_1 = (c + right.tag_1) % mod;
		root.tag_1 = 0;
	}
}

void build(int u, int l, int r)
{
	if(l == r)
	{
		tre[u] = {l, r};
		tre[u].tag_2 = 1;
		return;
	}
	int mid = l + r >> 1;
	tre[u] = {l, r};
	tre[u].tag_2 = 1;
	build(lson, l, mid);
	build(rson, mid + 1, r);
}

void modify(int u, int l, int r, int c, int op)
{
	if(tre[u].l >= l && tre[u].r <= r)
	{
		auto &root = tre[u];
		if(op == 1)
		{
			int s1 = root.sum1;
			int s2 = root.sum2;
			root.sum1 = (root.sum1 + (root.r - root.l + 1) * c) % mod;
			root.sum2 = (root.sum2 + 2 * s1 * c % mod + (root.r - root.l + 1) * c % mod * c % mod) % mod;
			root.sum3 = (root.sum3 + 3 * c * s2 % mod + 3 * s1 * c * c % mod + (root.r - root.l + 1) * c % mod * c * c % mod ) % mod;
			root.tag_1 = (c + root.tag_1) % mod;
		}
		else if(op == 2)
		{
			root.sum1 = root.sum1 * c % mod;	
			root.sum2 = root.sum2 * c * c % mod;
			root.sum3 = root.sum3 * c % mod * c % mod * c % mod;
			root.tag_2 = c * root.tag_2 % mod;
			root.tag_1 = c * root.tag_1 % mod;
		}
		else
		{
			root.sum1 = (root.r - root.l + 1) * c % mod;
			root.sum2 = (root.r - root.l + 1) * c * c % mod;
			root.sum3 = (root.r - root.l + 1) * c % mod * c % mod * c % mod;
			root.tag_3 = c;
			root.tag_1 = 0;
			root.tag_2 = 1;
		}
		return;
	}
	pushdown(u);
	int mid = tre[u].l + tre[u].r >> 1;
	if(l <= mid)
		modify(lson, l, r, c, op);

	if(r > mid)
		modify(rson, l, r, c, op);

	pushup(u);
}

int query(int u, int l, int r, int op)
{
	if(tre[u].l >= l && tre[u].r <= r)
	{
		if(op == 1)
			return tre[u].sum1;
		else if(op == 2)
			return tre[u].sum2;
		else
			return tre[u].sum3;
	}
	int mid = tre[u].l + tre[u].r >> 1;
	int res = 0;
	pushdown(u);
	if(l <= mid)
		res = (res + query(lson, l, r, op)) % mod;
	if(r > mid)
		res = (res + query(rson, l, r, op)) % mod;
	return res;
}

void solve()
{
	while(cin >> n >> m, n || m)
	{
		memset(tre, 0, sizeof tre);
		build(1, 1, n);
		while(m--)
		{
			int opt, l, r, c;
			cin >> opt >> l >> r >> c;
			if(opt != 4)
				modify(1, l, r, c, opt);
			else
				cout << query(1, l, r, c) << endl;
		}
	}
}

signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);

	solve();
}

到了这里,关于[HDU - 4578]Transformation(线段树+多重懒标记)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Windows多重连接问题

    先叙述我的问题出现情况: 我在Windows域账号中使用smb连接Linux服务器的共享文件夹时报多重连接的错,报错具体信息:“ 不允许一个用户使用一个以上用户名与服务器或共享资源的多重连接。中断与此服务器或共享资源的所有连接,然后再试一次 。” 查找并 测试过但不成

    2024年02月16日
    浏览(38)
  • 多重背包问题——单调队列优化

    我们在之前的文章中曾经讲解过多重背包问题,当时我们讲解了两种方法,一种方法就是三重循环,这种方法最为朴素好想。但是这种方法的时间复杂度非常高,后来我们想到了二进制优化的方式。那么今天我们将再介绍一种更好的优化方式——单调队列优化。 在讲解这种优

    2024年02月15日
    浏览(41)
  • 多重共线性问题如何解决?

    ​ 多重共线性一般是指:如果有两个或者多个自变量高度相关(相关系数大于0.8),难以区分一个自变量对因变量的影响和作用,将自变量相关性产生的后果定义为多重共线性,一般提出多重共线性问题,研究者往往会想到回归分析。回归分析方法,回归模型等,在统计学中

    2024年02月01日
    浏览(37)
  • 完全背包&多重背包问题(动态规划)

    完全背包问题: 每个物品使用次数没有限制,与0-1背包的不同之处在于 遍历背包的顺序 是正序。 多重背包问题: 与完全背包的区别在于,每一种物品是有个数限制的,不能无限选择。这篇博客讲解的非常详细,可以参考学习: 多重背包问题---超详细讲解+优化(不懂你揍我

    2024年04月10日
    浏览(47)
  • 动态规划DP之背包问题3---多重背包问题

    目录 DP分析: 优化:  二进制优化 例题:         01背包是每个物品只有一个,完全背包问题是每个物品有无限个。         那么多重背包问题就是 每个物品有有限个 。 有 N 种物品和一个容量是 V 的背包。 第 i 种物品最多有 si 件,每件体积是 vi,价值是 wi。 求解

    2024年03月20日
    浏览(49)
  • 多重背包问题(详解二进制优化原理)

    这道题同样是背包问题,那么它也同样满足三个性质:重叠子问题、最优子结构以及无后效性。那么这样的话,我们依然可以使用动态规划的思路去分析这道题目。那么动态规划的分析主要分为两步:状态转移方程的书写以及循环的设计。 (1)状态表示: 我们在前面的两篇

    2024年02月14日
    浏览(38)
  • 算法篇——动态规划 完全和多重背包问题 (js版)

    01 背包 问题和 完全背包 问题的不同点在于,所有的物品只能 使用一次 ,判断  哪些物品  装进背包里 物品价值和 最大;而 完全背包 问题中,所有物品都能 使用n次 ,判断 哪个物品 装 n 个进去 物品价值和 最大。 01 背包的递推公式是: 【当然先遍历物品还是背包的容量

    2024年02月08日
    浏览(45)
  • 蓝桥杯算法全集之多重背包问题I(动态规划算法)

    有 N 种物品和一个容量是 V 的背包。 第 i 种物品最多有 s i 件,每件体积是 v i ,价值是 w i 。 求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。 输出最大价值。 用下面这个图来分别动态规划的四个经典背包问题 定义状态的含义(这一步需要

    2023年04月08日
    浏览(41)
  • 【算法日志】动态规划刷题:01背包问题,多重背包问题(day37,day38)

    目录 前言 目标和(01背包) 一和零(01背包) 零钱兑换(多重背包) 排列总和(多重背包) 这两天都是背包问题,其中的01背包的一些应用问题需要一定的数学建模能力,需要i将实际问题简化成我们熟悉的背包问题;而这两天的多重背包问题还算比较基础,但也要我明白了

    2024年02月11日
    浏览(56)
  • 三十八、动态规划——背包问题( 01 背包 + 完全背包 + 多重背包 + 分组背包 + 优化)

    0 1 背包问题: 条件:N 个物品容量为 V 的背包,每件物品最多用 1 次,其中物品信息体积为 Vi,价值为 Wi。 目标:选出物品,使价值最大(不一定装满背包)。 特点:每件物品 最多只用 1 次 完全背包问题: 特点:每一件物品都有 无限个 多重背包问题: 特点:每个物品

    2024年02月07日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包