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 ...
随机推荐
- 【bzoj4383】[POI2015]Pustynia 线段树优化建图+差分约束系统+拓扑排序
题目描述 给定一个长度为n的正整数序列a,每个数都在1到10^9范围内,告诉你其中s个数,并给出m条信息,每条信息包含三个数l,r,k以及接下来k个正整数,表示a[l],a[l+1],...,a[r- ...
- 【bzoj2901】矩阵求和 前缀和
题目描述 给出两个n*n的矩阵,m次询问它们的积中给定子矩阵的数值和. 输入 第一行两个正整数n,m. 接下来n行,每行n个非负整数,表示第一个矩阵. 接下来n行,每行n个非负整数,表示第二个矩阵. ...
- SSD ECC中的LDPC编解码原理
转自:http://blog.csdn.net/zhuzongpeng/article/details/78899198 目前SSD中ECC纠错代码主要两种BCH和LDPC.不过,随着SSD对ECC纠 ...
- Vmware虚拟机三种网卡模式详解
由于Linux目前很热门,越来越多的人在学习linux,但是买一台服务放家里来学习,实在是很浪费.那么如何解决这个问题?虚拟机软件是很好的选择,常用的虚拟机软件有vmware workstations ...
- ElasticSearch API 之 DELETE
删除API,可以根据特定的ID删除文档. $ curl -XDELETE 'http://localhost:9200/website/blog/AVbkih8AltSLRRB7XAun' 会返回下面 ...
- 【BZOJ1305】dance跳舞(最大流,裂点,二分答案)
题意:一次舞会有n个男孩和n个女孩.每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞.每个男孩都不会和同一个女孩跳两首(或更多)舞曲. 有一些男孩女孩相互喜欢,而其他相互不喜欢(不会“单向喜欢”). ...
- AtCoder Regular Contest 074F - Lotus Leaves
$n \leq 300,m \leq 300$,$n*m$的格子里有起点有终点有空地有障碍,人会从起点选一个同行或同列空地跳过去,然后一直这样跳到终点.求至少删掉多少格子使得人跳不到终点. 首先S和T ...
- zoj 3627#模拟#枚举
Treasure Hunt II Time Limit: 2 Seconds Memory Limit: 65536 KB ...
- MongoDB 复制(副本集)学习
MongoDB 复制(副本集)学习 replication set复制集,复制集,多台服务器维护相同的数据副本,提高服务器的可用性.MongoDB复制是将数据同步在多个服务器的过程.复制提供了数据的冗 ...
- 不拖控件的asp.net编程方法——第1回
以前写的asp.net程序基本上都用了webfrom的控件编写的,当然有个好处就是易入门.快速效率高,但感觉自己这了几个小系统,还是没学到什么东西,感觉心里没底,因为都是封装好的东西,拿来就用的,功能 ...