线段树难题--史上最大值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
原创粉丝点击