【模板】 递归线段树 [2017年五月计划 清北学堂51精英班Day4]

P3372 【模板】线段树 1

题目描述

如题,已知一个数列,你需要进行下面两种操作:

1.将某区间每一个数加上x

2.求出某区间每一个数的和

输入输出格式

输入格式:

第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。

第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。

接下来M行每行包含3或4个整数,表示一个操作,具体如下:

操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k

操作2: 格式:2 x y 含义:输出区间[x,y]内每个数的和

输出格式:

输出包含若干行整数,即为所有操作2的结果。

输入输出样例

输入样例#1:

5 5
1 5 4 2 3
2 2 4
1 2 3 2
2 3 4
1 1 5 1
2 1 4

输出样例#1:

11
8
20

说明

时空限制:1000ms,128M

数据规模:

对于30%的数据:N<=8,M<=10

对于70%的数据:N<=1000,M<=10000

对于100%的数据:N<=100000,M<=100000

(数据已经过加强^_^,保证在int64/long long数据范围内)

样例说明:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include <algorithm>
  6 #define max(a,b) ((a) > (b) ? (a) : (b))
  7 #define min(a,b) ((a) > (b) ? (b) : (a))
  8 #define lowbit(a) (a & (-(a)))
  9 const int INF = 0x3f3f3f3f;
 10 const int MAXN = 100000 + 10;
 11 const int MAXM = 100000 + 10;
 12 inline void read(long long &x)
 13 {
 14     x = 0;char ch = getchar();char c = ch;
 15     while(ch > ‘9‘ || ch < ‘0‘)c = ch, ch = getchar();
 16     while(ch >= ‘0‘ && ch <= ‘9‘)x = x * 10 + ch - ‘0‘,ch = getchar();
 17     if(c == ‘-‘)x = -x;
 18 }
 19
 20 long long stdata[MAXN << 2];
 21 long long stlazy[MAXN << 2];
 22 long long n,m;
 23
 24
 25 void modify1(long long p, long long k, long long o = 1,long long l = 1,long long r = n)
 26 {
 27     if(l == r == p)
 28     {
 29         stdata[o] += k;
 30         return;
 31     }
 32     long long mid = (l + r) >> 1;
 33     if(p <= mid) modify1(p, k, o << 1, l, mid);
 34     else modify1(p, k, o << 1 | 1, mid + 1, r);
 35     stdata[o] = stdata[o << 1] + stdata[o << 1 | 1];
 36     return ;
 37 }
 38
 39
 40 void modify2(long long ll, long long rr, long long k, long long o = 1, long long l = 1, long long r = n)
 41 {
 42     if(l >= ll && r <= rr)
 43     {
 44         stlazy[o] += k;
 45         stdata[o] += (r - l + 1) * k;
 46         return;
 47     }
 48     if(ll <= l && rr <= r && rr >= l)
 49     {
 50         stdata[o] += k * (rr - l + 1);
 51     }
 52     else if(ll >= l && rr <= r)
 53     {
 54         stdata[o] += k * (rr - ll + 1);
 55     }
 56     else if(ll >= l && ll <= r && rr >= r)
 57     {
 58         stdata[o] += k * (r - ll + 1);
 59     }
 60     long long mid = (l + r) >> 1;
 61     if(ll <= mid)modify2(ll, rr, k, o << 1, l, mid);
 62     if(rr > mid) modify2(ll, rr, k, o << 1 | 1, mid + 1, r);
 63 }
 64
 65 long long query(long long ll, long long rr, long long o = 1, long long l = 1, long long r = n)
 66 {
 67     long long mid = (l + r) >> 1;
 68     if(ll <= l && rr >= r)
 69     {
 70         return stdata[o];
 71     }
 72     if(stlazy[o])
 73     {
 74         stlazy[o << 1] += stlazy[o];
 75         stlazy[o << 1 | 1] += stlazy[o];
 76         stdata[o << 1] += (mid - l + 1) * stlazy[o];
 77         stdata[o << 1 | 1] += (r - mid) * stlazy[o];
 78         stlazy[o] = 0;
 79     }
 80     long long ans = 0;
 81     if(ll <= mid)ans += query(ll, rr, o << 1, l, mid);
 82     if(rr > mid) ans += query(ll, rr, o << 1 | 1, mid + 1, r);
 83     stdata[o] = stdata[o << 1] + stdata[o << 1 | 1];
 84     return ans;
 85 }
 86
 87 long long num[MAXN];
 88 long long cnt;
 89 void build(long long o = 1,long long l = 1,long long r = n)
 90 {
 91     if(l == r)
 92     {
 93         stdata[o] = num[++cnt];
 94         return;
 95     }
 96     long long mid = (l + r) >> 1;
 97     build(o << 1, l, mid);
 98     build(o << 1 | 1, mid + 1, r);
 99     stdata[o] = stdata[o << 1] + stdata[o << 1 | 1];
100 }
101
102 long long tmp1,tmp2,tmp3,tmp4;
103
104 int main()
105 {
106     read(n);read(m);
107     for(long long i = 1;i <= n;i ++)
108     {
109         read(num[i]);
110     }
111     build();
112     for(long long i = 1;i <= m;i ++)
113     {
114         read(tmp1);
115         switch(tmp1)
116         {
117             case 1:
118                 {
119                     read(tmp1);read(tmp2);read(tmp3);
120                     modify2(tmp1, tmp2, tmp3);
121                     break;
122                 }
123             case 2:
124                 {
125                     read(tmp1);read(tmp2);
126                     printf("%lld\n", query(tmp1, tmp2));
127                 }
128         }
129     }
130     return 0;
131 }
时间: 2024-10-15 02:45:32

【模板】 递归线段树 [2017年五月计划 清北学堂51精英班Day4]的相关文章

【模板】倍增LCA [2017年5月计划 清北学堂51精英班 Day3]

P3379 [模板]最近公共祖先(LCA) 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询问a结点和b结点的最近公共祖先. 输出格式: 输出包含M行,每行包含一个正整数,依次为每一个询问的结果. 输入输出样例 输入

洛谷P1080 [NOIP2012提高组D1T2]国王游戏 [2017年5月计划 清北学堂51精英班Day1]

P1080 国王游戏 题目描述 恰逢 H 国国庆,国王邀请 n 位大臣来玩一个有奖游戏.首先,他让每个大臣在左.右 手上面分别写下一个整数,国王自己也在左.右手上各写一个整数.然后,让这 n 位大臣排 成一排,国王站在队伍的最前面.排好队后,所有的大臣都会获得国王奖赏的若干金币,每 位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右 手上的数,然后向下取整得到的结果. 国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序, 使得获得奖赏最多的大

P2327 [SCOI2005]扫雷 [2017年5月计划 清北学堂51精英班Day1]

P2327 [SCOI2005]扫雷 题目描述 输入输出格式 输入格式: 第一行为N,第二行有N个数,依次为第二列的格子中的数.(1<= N <= 10000) 输出格式: 一个数,即第一列中雷的摆放方案数. 输入输出样例 输入样例#1: 2 1 1 输出样例#1: 2 其实还是扫雷玩的少..知道思路之后很快 只需枚举前两个各自的情况,后面的各自便能够计算出来 注意几个细节(在代码里面) #include <iostream> #include <cstdio> #in

【模板】tyvjP1520 树的直径 [2017年5月计划 清北学堂Day3]

P1520 树的直径 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 树的直径,即这棵树中距离最远的两个结点的距离.每两个相邻的结点的距离为1,即父亲结点与儿子结点或儿子结点与父子结点之间的距离为1.有趣的是,从树 的任意一个结点a出发,走到距离最远的结点b,再从结点b出发,能够走的最远距离,就是树的直径.树中相邻两个结点的距离为1.你的任务是:给定一棵树, 求这棵树中距离最远的两个结点的距离. 输入格式 输入共n行第一行是一个正整数n,表示这棵树的结点

2017.7.21夏令营清北学堂解题报告

预计分数: 60+30+0=90=划水 实际分数: 90+30+20=140=rank5=雷蛇鼠标 一句话总结:今天该买彩票! T1: 题目描述 从前有一个?行?列的网格. 现在有?种颜色,第?种颜色可以涂??格,保证 Σ? ?? = ? * ?. 需要你对这个网格图进行着色,你必须按照从上到下,每一行内从左到右 的顺序进行着色,并且在用完一种颜色前你不能换颜色(当然颜色的使用顺序 是随意的). 每个相邻的相同色块可以获得1分,问在给定的规则下进行着色所能获得的 最高分是多少. 多组数据. 输入

关于树的一点学习【清北学堂】

我主要在这里讲的是树的直径求法和树的重心求法 树的直径,指的就是树上距离最远两点间的一条路径. 求树的直径的方法是,首先我任选一个点,找到与它距离最远的点,记为s 再以s为起点找离他最远的点,记为v s到v的路径即为树的直径 树的重心指的就是树上一个节点,把这个节点挖掉之后,剩下很多联通块  而重心就让这些联通块中最大的那个最小 树的重心有两种求法 一种是枚举每一个点 看把他挖掉之后会发生什么 第二种是DFS求出每个节点联通块大小 可能有人说每个节点不都连着整个树么 所以说这个联通块是算上节点自

【原创】洛谷 LUOGU P3373 【模板】线段树2

P3373 [模板]线段树 2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含三个整数N.M.P,分别表示该数列数字的个数.操作的总个数和模数. 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值. 接下来M行每行包含3或4个整数,表示一个操作,具体如下: 操作1: 格式:1 x y k 含义:将区间[x,y]内每个数乘上k 操作2: 格式:2 x

洛谷P3373 【模板】线段树 2

 P3373 [模板]线段树 2 47通过 186提交 题目提供者HansBug 标签 难度提高+/省选- 提交  讨论  题解 最新讨论 为啥WA(TAT) 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含三个整数N.M.P,分别表示该数列数字的个数.操作的总个数和模数. 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值. 接下来M行每行包含3或4

洛谷P3372 【模板】线段树 1

P3372 [模板]线段树 1 153通过 525提交 题目提供者HansBug 标签 难度普及+/提高 提交  讨论  题解 最新讨论 [模板]线段树1(AAAAAAAAA- [模板]线段树1 洛谷评测机出问题了吗? 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值. 接