Codeforces Round #179 (Div. 2) C Greg and Array 两个线段树
2015-07-25 21:14
218 查看
纯线段树的模板,只是要注意在计算加多少次的时候也当作线段树来做,注意longlong,为了保险我把所有int都改成了longlong
AC代码
后更:今天突然知道了一个非常屌的写法,用数组记录加减次数,加入数组为f,如果从i位置到j位置都加的话,就让f[i]++,f[j+1]--,最后再从1到n,f[i] += f[i-1],然后就能处理出来每次操作进行多少次了,同理,对上面值得修改也可以如此,附代码:
AC代码
#include<cstdio> #include<iostream> #include<cstring> #define maxn 100010 #define ls l,m,nod<<1 #define rs m+1,r,nod<<1|1 using namespace std; struct oper{ long long l; long long r; long long val; }op[maxn]; long long sum[maxn<<2],src[maxn]; long long flag[maxn<<2],n,q,m; void pushup(long long nod){ //此题不用,可有可无 sum[nod]=sum[nod<<1]+sum[nod<<1|1]; } void pushdown(long long nod,long long m){ if(flag[nod]) { flag[nod<<1]+=flag[nod]; flag[nod<<1|1]+=flag[nod]; sum[nod<<1]+=(long long)(m-(m>>1))*flag[nod]; sum[nod<<1|1]+=(long long)(m>>1)*flag[nod]; flag[nod]=0; } } void build(long long l,long long r,long long nod) { flag[nod]=0; if(l==r) { //cout<<nod; sum[nod] = 0; return; } long long m = (l+r)>>1; build(ls); build(rs); pushup(nod); } void update(long long ll,long long rr,long long val,long long l,long long r,long long nod) { if(l>=ll&&r<=rr) { flag[nod]+=val; sum[nod]+=(long long)(r-l+1)*val; return; } pushdown(nod,r-l+1); long long m=(l+r)>>1; if(ll<=m) update(ll,rr,val,ls); if(rr>m) update(ll,rr,val,rs); pushup(nod); } long long query(long long ql,long long qr,long long l,long long r,long long nod){ long long summ=0,ta=0,tb=0; if(l>=ql&&r<=qr) {summ+=sum[nod]; return summ;} pushdown(nod,r-l+1); long long m=(l+r)>>1; if(ql<=m) ta=query(ql,qr,ls); if(qr>m) tb=query(ql,qr,rs); summ+=ta; summ+=tb; return summ; } int main(){ memset(sum,0,sizeof(sum)); scanf("%lld%lld%lld",&n,&m,&q); for(int i = 1; i <= n; i++) scanf("%lld",&src[i]); for(int i = 1; i <= m; i++) scanf("%lld%lld%lld",&op[i].l,&op[i].r,&op[i].val); build(1,m,1); long long a,b,v; /*for(int i = 0; i < 40; i++) cout<<sum[i]<<" ";*/ while(q--) { scanf("%lld%lld",&a,&b); update(a,b,1,1,m,1); } for(int i = 1; i <= m; i++) op[i].val*=query(i,i,1,m,1); memset(sum,0,sizeof(sum)); build(1,n,1); for(int i = 1; i <= m; i++) update(op[i].l,op[i].r,op[i].val,1,n,1); printf("%lld",query(1,1,1,n,1) + src[1]); for(int i = 2; i <= n; i++) printf(" %lld",query(i,i,1,n,1) + src[i]); printf("\n"); }
后更:今天突然知道了一个非常屌的写法,用数组记录加减次数,加入数组为f,如果从i位置到j位置都加的话,就让f[i]++,f[j+1]--,最后再从1到n,f[i] += f[i-1],然后就能处理出来每次操作进行多少次了,同理,对上面值得修改也可以如此,附代码:
#include <iostream> #include <cstdio> #include <algorithm> #define maxn 100010 using namespace std; long long a[maxn],d[maxn],g[maxn]; int n,m,k,x,y,l[maxn],r[maxn],f[maxn]; int main(){ cin>>m>>n>>k; for(int i = 1; i <= m; i++) scanf("%lld",a+i); for(int i = 1; i <= n; i++) scanf("%d%d%lld",l+i,r+i,d+i); for(int i = 1; i <= k; i++) scanf("%d%d",&x,&y),f[x]++,f[y+1]--; //与下一步结合起来做,代表从x到y这个区间内所有的值都加了一 for(int i = 1; i <= n; i++) f[i] += f[i-1]; for(int i = 1; i <= n; i++) g[l[i]]+=d[i]*f[i],g[r[i] + 1]-=d[i]*f[i]; //同上 for(int i = 1; i <= m; i++) g[i]+=g[i-1]; for(int i = 1; i <= m; i++) printf("%lld ",g[i] + a[i]); }
相关文章推荐
- F - Ilya Muromets-
- Web前端从入门到精通-8 css简介——清除浮动
- css图片实现水平、垂直居中
- 数字图像处理入门
- 字符编码的总体认识及若干问题
- (面试题)删除在另一个字符串中出现的字符
- Hive desc
- JVM类加载器(双亲委托模型)
- URL中的保留和不安全字符
- 做一个优雅的程序员
- redmine和svn server的部署
- N!
- JAVA笔记之环境配置
- Delphi7学习第二天
- view的触摸事件OnTouch与监听
- LeetCode_1 TwoSum
- ADT、SDK、eclipse、集成开发工具
- setObject设置boolean的类型为啥不行?
- 【MySQL案件】ERROR 1418
- 二叉树的非递归遍历