codevs线段树练习5(双重标记)
来源:互联网 发布:jquery 对象数组 编辑:程序博客网 时间:2024/06/05 08:05
有n个数和5种操作
add a b c:把区间[a,b]内的所有数都增加c
set a b c:把区间[a,b]内的所有数都设为c
sum a b:查询区间[a,b]的区间和
max a b:查询区间[a,b]的最大值
min a,b:查询区间[a,b]的最小值
双标记,注意双标记间的关系即可,注意一下,不是很难,顺便练代码能力,可惜一次编完,还是有两个地方没考虑到
对于线段树add的部分,以后一定要再注意再注意!add可能会多次,所以要用+=
a【i】.add+=add;!!!!
set用一个bool来判断是否被区间赋值,更方便,且不会有bug。
#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<cstdlib>using namespace std;typedef long long ll;const ll inf=100000000000ll;//pay attention to 'll'int n,m;struct aa{ll mx,mi,sum,add;int l,r,set;}a[400005+1000];void up(int i){a[i].mi=inf;a[i].mx=-inf;a[i].sum=0;if (a[i<<1].l){a[i].mi=min(a[i].mi,a[i<<1].mi);a[i].mx=max(a[i].mx,a[i<<1].mx);a[i].sum+=a[i<<1].sum;}if (a[i<<1|1].l){a[i].mi=min(a[i].mi,a[i<<1|1].mi);a[i].mx=max(a[i].mx,a[i<<1|1].mx);a[i].sum+=a[i<<1|1].sum;}}void down(int i){if (a[i].set){a[i<<1].set=a[i<<1|1].set=1;a[i<<1].add=a[i<<1|1].add=0;ll st=a[i].mi;a[i<<1].sum=st*(a[i<<1].r-a[i<<1].l+1);a[i<<1|1].sum=st*(a[i<<1|1].r-a[i<<1|1].l+1);a[i<<1].mi=a[i<<1|1].mi=a[i<<1].mx=a[i<<1|1].mx=st;a[i].set=0;}if (a[i].add){ll ad=a[i].add;a[i<<1].mi+=ad;a[i<<1].mx+=ad;a[i<<1].sum+=(a[i<<1].r-a[i<<1].l+1)*ad;if (a[i<<1].set==0) a[i<<1].add+=ad; a[i<<1|1].mi+=ad;a[i<<1|1].mx+=ad;a[i<<1|1].sum+=(a[i<<1|1].r-a[i<<1|1].l+1)*ad;if (a[i<<1|1].set==0) a[i<<1|1].add+=ad;//这个地方一定要用 += ,因为可能重复加//这个错误犯了好多次了!!,要非常注意 a[i].add=0;}}void build(int i,int l,int r){a[i].l=l;a[i].r=r;if (l==r){ll x;scanf("%lld",&x);a[i].mx=a[i].mi=a[i].sum=x;return ;}int mid=(l+r)>>1;build(i<<1,l,mid);build(i<<1|1,mid+1,r);up(i);}void add(int i,int l,int r,ll ad){if (a[i].l==l&&a[i].r==r){a[i].sum+=(a[i].r-a[i].l+1)*ad;a[i].mx+=ad;a[i].mi+=ad;if (a[i].set) return ;a[i].add+=ad;//这个地方一定要用 += ,因为可能重复加return ;}down(i);int mid=(a[i].l+a[i].r)>>1;if (mid>=r) add(i<<1,l,r,ad);else if (mid<l) add(i<<1|1,l,r,ad);else add(i<<1,l,mid,ad),add(i<<1|1,mid+1,r,ad);up(i);}void set(int i,int l,int r,ll st){if (a[i].l==l&&a[i].r==r){a[i].set=1;a[i].sum=st*(a[i].r-a[i].l+1);a[i].mx=a[i].mi=st;a[i].add=0;return ;}down(i);int mid=(a[i].l+a[i].r)>>1;if (mid>=r) set(i<<1,l,r,st);else if (mid<l) set(i<<1|1,l,r,st);else set(i<<1,l,mid,st),set(i<<1|1,mid+1,r,st);up(i);}ll sum(int i,int l,int r){if (a[i].l==l&&a[i].r==r) return a[i].sum;down(i);int mid=(a[i].l+a[i].r)>>1;if (mid>=r) return sum(i<<1,l,r);else if (mid<l) return sum(i<<1|1,l,r);return sum(i<<1,l,mid)+sum(i<<1|1,mid+1,r);}ll findmx(int i,int l,int r){if (a[i].l==l&&a[i].r==r) return a[i].mx;down(i);int mid=(a[i].l+a[i].r)>>1;if (mid>=r) return findmx(i<<1,l,r);else if (mid<l) return findmx(i<<1|1,l,r);return max(findmx(i<<1,l,mid),findmx(i<<1|1,mid+1,r));}ll findmi(int i,int l,int r){if (a[i].l==l&&a[i].r==r) return a[i].mi;down(i);int mid=(a[i].l+a[i].r)>>1;if (mid>=r) return findmi(i<<1,l,r);else if (mid<l) return findmi(i<<1|1,l,r);return min(findmi(i<<1,l,mid),findmi(i<<1|1,mid+1,r));}int main(){scanf("%d%d",&n,&m);build(1,1,n);char s[10];int x,y;ll z;while (m--){scanf("%s",s);scanf("%d%d",&x,&y);switch(s[1]){case 'd':scanf("%lld",&z);add(1,x,y,z);break;//addcase 'e':scanf("%lld",&z);set(1,x,y,z);break;//setcase 'u':printf("%lld\n",sum(1,x,y));break;//sumcase 'a':printf("%lld\n",findmx(1,x,y));break;//maxcase 'i':printf("%lld\n",findmi(1,x,y));break;//min}}return 0;}
总结
1:关于线段树,splay,lct等等的数据结构中,太多都要用到up和down函数,关于down的顺序其实是需要注意的。
首先我们在打标记的时候,同时就要更新标记本身这个节点的答案(such as sum【i】,mx【i】)并不是要等到,push_down的时候再处理本身这个节点的,push_down的时候只处理他的孩子节点(的sum,mx……),跟它本身节点的值已经没关系了,他本身节点的值已经更新过了。
0 0
- codevs线段树练习5(双重标记)
- Codevs 4927 线段树练习5(分块)
- Codevs 4927 线段树练习5
- <线段树系列4> codevs 4927 线段树练习5
- codevs线段树练习3
- [codevs] 线段树练习4
- CODEVS 1080线段树练习
- 1080 线段树练习 codevs
- CODEVS 1080 线段树练习
- [Codevs] 1080 线段树练习
- 【codevs 1080】线段树练习
- codevs 1080~1082 线段树练习系列(模板)
- 【codevs 1080】线段树练习(单点修改+区间和)
- CODEVS-1082-线段树练习3-splay
- 【codevs 1080~1082】线段树练习重做
- 【codevs 1082】线段树练习3
- CODEVS 1081线段树练习2
- [题解] codevs 1080 线段树练习
- Swift 学习2
- 第二章:快速入门
- CodeForces 599C Day at the Beach
- Android开发笔记之ViewPage实现导航页原理
- sort之结构体排序2
- codevs线段树练习5(双重标记)
- Java和C语言,C++语言主要差别
- mybatis分页插件
- HTML 5实现图像走马灯效果
- C++builder Property属性
- 为什么 Git 比 SVN 好
- compareTo返回值为-1 、 1 、 0 的排序问题
- google hacking搜索语法总结
- MySQL的source命令不加分号和delimiter的使用