洛谷P3372 线段树1【模板】
2017-12-26 23:11
399 查看
题目
题目描述
如题,已知一个数列,你需要进行下面两种操作: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的结果。输入输出样例
输入
5 51 5 4 2 3
2 2 4
1 2 3 2
2 3 4
1 1 5 1
2 1 4
输出
118
20
说明
时空限制:1000ms,128M数据规模:
对于30%的数据:N<=8,M<=10
对于70%的数据:N<=1000,M<=10000
对于100%的数据:N<=100000,M<=100000
分析
翻译过来就是:给你一颗线段树,区间修改或区间查询。lazy标记法。
#include <cstdio> #include <iostream> #include <algorithm> #include <queue> #include <cmath> #include <cstring> #include <vector> #include <cstdlib> #include <ctime> //日常头文件 using namespace std; //依然头文件 typedef long long ll; //懒得打 const int N=100900; //数据范围 ll ans; //可能很大 ll a ; //可能很大 struct node { ll sum; ll addv; }; node v[N*4]; void Add(ll,ll,ll,ll); //操作2第二步 void pushdown(ll,ll,ll); //向下 void pushup(ll); //向上 void buitre(ll,ll,ll); //建树 ll Query(ll,ll,ll,ll,ll); //区间查询 void update(ll,ll,ll,ll,ll,ll); //区间修改 int main() { int n; int m; scanf("%d",&n); scanf("%d",&m); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); //以上不解释 buitre(1,n,1); //建树 for(int i=1;i<=m;i++) { int opt; scanf("%d",&opt); if(opt==1) { int x; int y; int k; scanf("%d",&x); scanf("%d",&y); scanf("%d",&k); update(x,y,k,1,n,1); } else//我不信还有第三个操作嘎哈哈 { int x; int y; scanf("%d",&x); scanf("%d",&y); ll answ; answ=Query(x,y,1,n,1); printf("%lld\n",answ); } //分开写是因为读入的数的个数不一样 //也可以强制性写一起 } //处理操作 return 0; } void Add(ll l,ll r,ll C,ll rt) { v[rt].sum+=(r-l+1)*C; v[rt].addv+=C; } void pushdown(ll l,ll r,ll rt) { ll mid; mid=(l+r)/2; if(v[rt].addv) { ll C; C=v[rt].addv; Add(l,mid,C,rt<<1); Add(mid+1,r,C,rt<<1|1); v[rt].addv=0; } } void pushup(ll rt) { v[rt].sum=v[rt*2].sum+v[rt*2+1].sum; } void buitre(ll l,ll r,ll rt) { if(l==r) { v[rt].sum=a[l]; return; } ll mid; mid=(l+r)/2; buitre(l,mid,2*rt); buitre(mid+1,r,2*rt+1); pushup(rt); } ll Query(ll L,ll R,ll l,ll r,ll rt) { if(L<=l&&r<=R) return v[rt].sum; ll mid; ll ans; mid=(l+r)>>1; ans=0; pushdown(l,r,rt); if(L<=mid) ans+=Query(L,R,l,mid,rt<<1); if(R>mid) ans+=Query(L,R,mid+1,r,rt<<1|1); return ans; } void update(ll L,ll R,ll C,ll l,ll r,ll rt) { if(L<=l&&r<=R) { Add(l,r,C,rt); return; } ll mid; mid=(l+r)>>1; pushdown(l,r,rt); if(L<=mid) update(L,R,C,l,mid,rt<<1); if(R>mid) update(L,R,C,mid+1,r,rt<<1|1); pushup(rt); } //哦,好长 //妈呀终于完事了调了半天我去
相关文章推荐
- 洛谷P3372 【模板】线段树 1
- 【洛谷P3372】【模板】线段树1
- 洛谷P3372 【模板】线段树 1(lazy)
- 【洛谷P3372】【模板】线段树 1
- 洛谷P3372 【模板】线段树 1
- POJ 3468 A Simple Problem with Integers (线段树区间更新模板题)
- 模板_线段树
- 洛谷.3834.[模板]可持久化线段树(主席树 静态区间第k小)
- 线段树模板
- 线段树 面积并 模板题
- POJ 3667 Hotel(线段树 区间合并 模板题)
- 线段树 模板
- 【成端更新线段树模板】POJ3468-A Simple Problem with Integers
- 线段树模板
- 洛谷OJ U552 守墓人 线段树模板题
- 洛谷 2068 线段树模板:单点更新,区间求和
- hdu1166 线段树模板
- 线段树模板
- BZOJ 1798 [Ahoi2009]Seq 维护序列seq 线段树模板
- HDU 1823 Luck and Love (二维线段树模板)