线段树难题--史上最大值nkoj3726
来源:互联网 发布:淘宝直销 编辑:程序博客网 时间:2024/06/03 22:02
P3726史上最大值
时间限制 : - MS 空间限制 : 165536 KB
问题描述
给出一个长度为n的序列,一开始序列中每个数字都为0。现在有两种操作:
1.将区间[x,y]的数字都加上一个整数d(0<d<=10000);
2.将区间[x,y]的数字都置为0
操作共进行了m次,问操作结束后,数列中每个数字在这m次操作过程中,出现过的最大值是多少?即历史上出现过的最大值。
输入格式
第一行,一个两个整数n和m,(1<=n,m<=100000)
接下来m行,每行第一个整数为z,表示操作类型,
z=1表示1号操作,后面三个整数x,y和d
z=2表示2号操作,后面两个整数x,y
输出格式
一行,n个整数,表示数列中,每个数字历史上出现过的最大值。
样例输入 1
5 4
1 2 4 3
1 3 5 1
2 1 5
1 1 4 2
样例输出 1
2 3 4 4 1
样例输入 2
10 10
1 7 9 8
1 6 10 1
2 6 9
1 5 8 3
1 2 3 5
2 1 5
1 2 10 5
2 5 9
1 6 9 7
1 1 9 3
样例输出 2
3 8 8 8 5 10 10 10 10 6
分析:首先想到:建两颗线段树?一个维持最大值,一个维持历史最大值?转移不了?想另外方法!
上述想法是横起看,那么我们试试竖起看,把每次操作横起排下来,带上权值:
例如:
1|------------------------------|10 这是要操作的区间
2|-------|4 (加上5)
3|------------|6 (清0)
1|--------------|5 (加上5)
4|-----------|7 (加上2)
对于x=4我们看到:进行的操作共有4次:1. +5 2.清0 3. +5 4. +2。
如何处理?清0明显是一种分界线,应该前后分开求!
仔细想一下:我们把在 某个点上进行的操作按照先后顺序排好
问题就转化为了求最大连续和,其中连续区间不含清0操作
最大连续和:线段树!!!
注意清0操作的一个小技巧:因为最大连续和中不能包含清0,可以在清0操作上
赋值为-inf,这样求出来的最大连续和自然就不包括清0操作了。
另外:求完一个点,线段树向右平移一个单位,删去移除区间的操作,添加新进入区间的操作。
可以用类似于存边的方式把每个操作按照起始位置链起来,就很简单了。
详情请参见代码!!!
举个例子:图中为x=4的情况
如有问题,请联系1879570236.
#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib> #include<algorithm>#define inf 88888888using namespace std;const long long maxn=100005;long long triplemax(long long a,long long b,long long c){return max(a,max(b,c));}struct node{long long a,b;long long l1,r1,mid1,max1;long long sum;}; node tree[maxn*4];long long a[maxn];long long n,m;void update(long long p){long long l=(p<<1),r=(p<<1)+1;tree[p].sum=tree[l].sum+tree[r].sum;tree[p].l1=max(tree[l].l1,tree[l].sum+tree[r].l1);tree[p].r1=max(tree[r].r1,tree[r].sum+tree[l].r1);tree[p].max1=triplemax(tree[l].max1,tree[r].max1,tree[l].r1+tree[r].l1);}void build_tree(long long p,long long x,long long y){tree[p].a=x;tree[p].b=y;if(x<y){build_tree(p<<1,x,(x+y)>>1);build_tree((p<<1)+1,((x+y)>>1)+1,y);}}void add(long long p,long long k,long long d){if(tree[p].a>k||tree[p].b<k)return;if(tree[p].a==tree[p].b){tree[p].l1=d;tree[p].r1=d;tree[p].mid1=d;tree[p].max1=d;tree[p].sum=d;return;}if(tree[(p<<1)].a<=k&&k<=tree[(p<<1)].b){add((p<<1),k,d);}if(tree[(p<<1)+1].a<=k&&k<=tree[(p<<1)+1].b){add((p<<1)+1,k,d);}update(p);}long long getsum(long long p,long long x,long long y){if(tree[p].b<x||tree[p].a>y)return 0;if(tree[p].b<=y&&tree[p].a>=x)return tree[p].sum;else{long long total=0;total+=getsum((p<<1),x,y);total+=getsum(((p<<1)+1),x,y);return total;}}long long lastl[100005],lastr[100005],nextl[100005],nextr[100005];struct node2{long long l,r,d,id;};node2 change[100005];long long ans[100005];int main(){//freopen("data.in","r",stdin);//freopen("std1.out","w",stdout);long long i,j,k;cin>>n>>m;build_tree(1,1,m);for(i=1;i<=m;i++){long long z,x,y,dd;scanf("%I64d%I64d%I64d",&z,&x,&y);if(z==2)dd=-inf;else scanf("%I64d",&dd);change[i].l=x;change[i].r=y;change[i].d=dd;change[i].id=i;nextl[i]=lastl[x];lastl[x]=i;nextr[i]=lastr[y];lastr[y]=i;}for(i=1;i<=n;i++){for(long long h=lastl[i];h;h=nextl[h]){add(1,change[h].id,change[h].d);}ans[i]=tree[1].max1;for(long long h=lastr[i];h;h=nextr[h]){add(1,change[h].id,0);}}for(i=1;i<=n;i++){printf("%I64d ",ans[i]);}}
0 0
- 线段树难题--史上最大值nkoj3726
- 【趣题】【"竖着的"线段树】NKOJ 3726 史上最大值
- hdu3308 LCIS 线段树 难题
- hdu1823 二维线段树~最大值
- 线段树求区间最大值
- 线段树区间求最大值
- 线段树区间和最大值
- 线段树求区间最大值
- 【线段树】最大值(单点)
- 洛谷1198 最大值 线段树
- hdu1540 Tunnel Warfare 线段树中等难题
- hdu1754-线段树(求区间最大值)
- hdu1754 初探线段树之区间最大值、
- hdu1754线段树维护区间最大值
- 线段树维护区间最大值hdu1754
- 二维线段树维护最大值hdu1823
- HDU1823 二维线段树 求最大值
- poj3264 线段树维护最大值最小值
- 7.21:对Cocos中精灵的理解
- SpringMVC + mybatis结合
- android开发中的MVP详解
- HDU 1253
- 暑假集训--训练1 二分搜索
- 线段树难题--史上最大值nkoj3726
- Android拍照和获取相册图片
- 字符串搜索之KMP算法(伪代码)
- 前端开发必备插件
- 遇到:无法解析类型 java.lang.CharSequence怎么办?
- Android 如何编写基于编译时注解的项目
- 2016年团体程序设计天梯赛-决赛 L2-014. 列车调度 【导弹拦截系统-最长上升子序列nlogn求法】
- 13A - Numbers
- Linux入门(一)-目录和文件系统