luogu3373 【模板】线段树2
题目大意:
已知一个数列,你需要进行下面三种操作:
1.将某区间每一个数乘上x
2.将某区间每一个数加上x
3.求出某区间每一个数的和
本线段树的标记是个二元组:add和mul,其代表将一个线段中的每一个点乘以mul再加add。设区间长度为x,原来区间和为sum。如果两个标记要叠加,标记叠加前区间上的和将是sum*mul+add,叠加后的值将是(sum*mul+add)*mul'+add'=mul*mul'*sum+add*mul'+add'。所以将mul*=mul', add=add*mul'+add'即可。
注意:
- 尽管数据关于P取模了,但是因为有数据相乘的操作,所以程序中所有的值类型都要是long long
- 宏定义ModPlus, ModMult时,如ModMult,不要写成((x%P)*(y%P))%P,应该写成(x*y)%P,否则就被卡常数了。
#include <cstdio>
#include <cstring>
#include <cassert>
using namespace std; const int MAX_RANGE=100010, MAX_NODE = MAX_RANGE * 4;
#define LOOP(i, n) for(int i=1; i<=n; i++)
long long P, TotRange;
long long OrgData[MAX_RANGE]; struct RangeTree
{
private:
#define ModPlus(x, y) ((x)%P+(y)%P)%P
#define ModMult(x, y) ((x)%P*(y)%P)%P
#define lSon cur*2, l, mid
#define rSon cur*2+1, mid+1, r
#define Lson cur*2, sl, mid, al, ar
#define Rson cur*2+1, mid+1, sr, al, ar struct Tag
{
long long add, mul;
Tag() {}
Tag(int m, int a):mul(m),add(a){}
void Refresh(Tag x) { mul = ModMult(mul, x.mul); add = ModMult(add, x.mul); add = ModPlus(add, x.add); }
void Clear() { add = 0; mul = 1; }
int GetSum(int sum, int l, int r) { return ModPlus(ModMult(sum, mul), ModMult(add, (r - l + 1))); }
};
Tag _tags[MAX_NODE];
long long Sum[MAX_NODE]; void PushDown(int cur, int l, int r)
{
if (_tags[cur].add != 0 || _tags[cur].mul != 1)
{
int mid = (l + r) / 2;
Sum[cur * 2] = _tags[cur].GetSum(Sum[cur * 2], l, mid);
Sum[cur * 2 + 1] = _tags[cur].GetSum(Sum[cur * 2 + 1], mid + 1, r);
_tags[cur * 2].Refresh(_tags[cur]);
_tags[cur * 2 + 1].Refresh(_tags[cur]);
_tags[cur].Clear();
}
} void PullUp(int cur)
{
Sum[cur] = ModPlus(Sum[cur * 2], Sum[cur * 2 + 1]);
} void Update(int cur, int sl, int sr, int al, int ar, int op, int value)
{
assert(al <= ar && sl <= sr && al <= sr && ar >= sl);
if (al <= sl && sr <= ar)
{
if (op == 1)
{
Sum[cur] = ModMult(Sum[cur], value);
_tags[cur].Refresh(Tag(value, 0));
}
else if (op == 2)
{
Sum[cur] = ModPlus(Sum[cur], (sr - sl + 1)*value);
_tags[cur].Refresh(Tag(1, value));
}
return;
}
PushDown(cur, sl, sr);
int mid = (sl + sr) / 2;
if (al <= mid)
Update(Lson, op, value);
if (ar > mid)
Update(Rson, op, value);
PullUp(cur);
} int Query(int cur, int sl, int sr, int al, int ar)
{
assert(al <= ar && sl <= sr && al <= sr && ar >= sl);
if (al <= sl && sr <= ar)
return Sum[cur];
PushDown(cur, sl, sr);
int mid = (sl + sr) / 2, ans = 0;
if (al <= mid)
ans = ModPlus(ans, Query(Lson));
if (ar > mid)
ans = ModPlus(ans, Query(Rson));
PullUp(cur);
return ans;
} void SetEachNode(long long *a, int cur, int l, int r)
{
_tags[cur] = Tag(1, 0);
if (l == r)
{
Sum[cur] = a[l];
return;
}
int mid = (l + r) / 2;
SetEachNode(a, lSon);
SetEachNode(a, rSon);
PullUp(cur);
} public:
RangeTree() {} void SetEachNode(long long *a)
{
SetEachNode(a, 1, 1, TotRange);
} void Update(int l, int r, int op, int value)
{
Update(1, 1, TotRange, l, r, op, value);
} long long Query(int l, int r)
{
return Query(1, 1, TotRange, l, r);
}
}g; int main()
{
int opCnt, op, l, r, val;
scanf("%lld%d%lld", &TotRange, &opCnt, &P);
LOOP(i, TotRange)
scanf("%lld", OrgData + i);
g.SetEachNode(OrgData);
while (opCnt--)
{
scanf("%d", &op);
switch (op)
{
case 1://Mult
scanf("%d%d%d", &l, &r, &val);
g.Update(l, r, 1, val);
break;
case 2://Plus
scanf("%d%d%d", &l, &r, &val);
g.Update(l, r, 2, val);
break;
case 3://Query
scanf("%d%d", &l, &r);
printf("%lld\n", g.Query(l, r));
break;
}
}
return 0;
}
luogu3373 【模板】线段树2的更多相关文章
- hdu 1754 I Hate It (模板线段树)
http://acm.hdu.edu.cn/showproblem.php?pid=1754 I Hate It Time Limit: 9000/3000 MS (Java/Others) M ...
- 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)
To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...
- hdu3966 树链剖分点权模板+线段树区间更新/树状数组区间更新单点查询
点权树的模板题,另外发现树状数组也是可以区间更新的.. 注意在对链进行操作时方向不要搞错 线段树版本 #include<bits/stdc++.h> using namespace std ...
- 【线段树】【P3372】模板-线段树
百度百科 Definition&Solution 线段树是一种log级别的树形结构,可以处理区间修改以及区间查询问题.期望情况下,复杂度为O(nlogn). 核心思想见百度百科,线段树即将每个 ...
- 算法模板——线段树6(二维线段树:区域加法+区域求和)(求助phile)
实现功能——对于一个N×M的方格,1:输入一个区域,将此区域全部值作加法:2:输入一个区域,求此区域全部值的和 其实和一维线段树同理,只是不知道为什么速度比想象的慢那么多,求解释...@acphile ...
- 【洛谷 p3373】模板-线段树 2(数据结构--线段树)
题意:已知一个数列,你需要进行下面三种操作:1.将某区间每一个数加上x:2.将某区间每一个数乘上x:3.求出某区间每一个数的和. 解法:(唉 :-(,这题卡住我了......)对于加法和乘法的混合操作 ...
- 【洛谷 p3372】模板-线段树 1(数据结构--线段树)
题目:已知一个数列,你需要进行下面两种操作:1.将某区间每一个数加上x:2.求出某区间每一个数的和. 解法:如题,模版题.需要加上 lazy 标记,也就是我的 upd.lazy 标记的思路就是对一个结 ...
- hdu 1754 I Hate It (线段树、单点更新)(PS:ios::sync_with_stdio(false)可以加快cin、cout的读取写出速度)
I Hate ItTime Limit: 9000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Su ...
- poj 3468 A Simple Problem with Integers 线段树 题解《挑战程序设计竞赛》
地址 http://poj.org/problem?id=3468 线段树模板 要背下此模板 线段树 #include <iostream> #include <vector> ...
- 线段树 扫描线 L - Atlantis HDU - 1542 M - City Horizon POJ - 3277 N - Paint the Wall HDU - 1543
学习博客推荐——线段树+扫描线(有关扫描线的理解) 我觉得要注意的几点 1 我的模板线段树的叶子节点存的都是 x[L]~x[L+1] 2 如果没有必要这个lazy 标志是可以不下传的 也就省了一个pu ...
随机推荐
- GFS, HDFS, Blob File System架构对比
分布式文件系统很多,包括GFS,HDFS,淘宝开源的TFS,Tencent用于相册存储的TFS (Tencent FS,为了便于区别,后续称为QFS),以及Facebook Haystack.其中,T ...
- 虚拟机vmnet0、vmnet1和vmnet8的区别 虚拟网卡概述
vmnet0,实际上就是一个虚拟的网桥 vmnet0,实际上就是一个虚拟的网桥,这个网桥有很若干个端口,一个端口用于连接你的Host,一个端口用于连接你的虚拟机,他们的位置是对等的,谁也不是谁的网关. ...
- Codevs 1043 ==洛谷 P1004 方格取数
题目描述 设有N*N的方格图(N<=9),我们将其中的某些方格中填入正整数,而其他的方格中则放 人数字0.如下图所示(见样例): A 0 0 0 0 0 0 0 0 0 0 13 0 0 6 0 ...
- Python入门--1--基本中的基本
一. 1.这是一个面向对面的编程,一种解释性语言. 2.缩进是python的灵魂,使代码变得非常简洁,正确使用冒号“:”,IDLE的 下一行会自动缩进 3.if语句中 python拒绝接受 ...
- 【编码】封装RedisPubSub工具
基本介绍 核心原理:利用Redis的List列表实现,发布事件对应rpush,订阅事件对应lpop 问题一:Redis不是自带Pub/Sub吗? redis自带的pub/sub有两个问题: 1.如果发 ...
- Codeforces Round #321 (Div. 2) E
终于补好了. 题目链接: http://codeforces.com/contest/580/problem/E E. Kefa and Watch time limit per test 1 sec ...
- NSTimer与NSRunLoop的关系分析
NSTimer与NSRunLoop的关系分析 发表于 2013 年 6 月 27 日 由 bluev | 6 次浏览 最近关于NSTimer和NSRunLoop的关系,做了一个小试验.代码地址:htt ...
- Xib/Storyboard碰到不同版本的Xcode真是想死啊!
Command /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/ ...
- 常用Git命令手册
常用Git命令手册 此文只是对Git有一定基础的人当记忆使用,比较简略,初级学员强烈推荐廖雪峰老师的Git系列教程,通俗易懂,戳此处即可开始学习 1.安装Git Linux sudo apt-get ...
- [转]Go基础之锁的初识
当我们的程序就一个线程的时候是不需要用到锁的,但是通常我们实际的代码不会是单个线程的,所有这个时候就需要用到锁了,那么关于锁的使用场景主要涉及到哪些呢? 当我们多个线程在读相同的数据的时候则是需要加锁 ...