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)
我们看到:进行的操作共有4次:+5 清0 +5 +2。
清0明显是一种分界线,应该前后分开求!
我们把在 某个点上进行的操作按照先后顺序排好,问题就转化为了求最大连续和,其中连续区间不含清0操作
求最大连续和我们显然就应该用线段树来求
注意清0操作的一个小技巧:因为最大连续和中不能包含清0,可以在清0操作上
赋值为-inf,这样求出来的最大连续和自然就不包括清0操作了。
另外:求完一个点,线段树向右平移一个单位,删去移除区间的操作,添加新进入区间的操作。
可以用类似于存边的方式把每个操作按照起始位置链起来,就很简单了。
#include<cstdio>
#include<iostream>
#include<vector>
#define LL long long
using namespace std;
const int maxn=100005;
LL n,m,qust[maxn],tot=1,k,a,b,d,num,p;
vector<LL>fron[maxn],bac[maxn];
struct wk{LL lm,rm,maxx,sum;}tree[maxn<<2];
inline void _read(LL &x){
char ch=getchar(); bool mark=false;
for(;!isdigit(ch);ch=getchar())if(ch=='-')mark=true;
for(x=0;isdigit(ch);ch=getchar())x=x*10+ch-'0';
if(mark)x=-x;
}
void update(LL r){
LL ls=r<<1,rs=(r<<1)+1;
tree[r].sum=tree[ls].sum+tree[rs].sum;
tree[r].lm=max(tree[ls].lm,tree[ls].sum+tree[rs].lm);
tree[r].rm=max(tree[rs].rm,tree[rs].sum+tree[ls].rm);
tree[r].maxx=max(max(tree[ls].maxx,tree[rs].maxx),tree[ls].rm+tree[rs].lm);
}
void change(LL r,LL x,LL y){
if(x==y){
tree[r].maxx=tree[r].lm=tree[r].rm=tree[r].sum=d;
return;
}
LL mid=(x+y)>>1,ls=r<<1,rs=(r<<1)+1;
if(p<=mid)change(ls,x,mid);
else change(rs,mid+1,y);
update(r);
}
int main(){
_read(n);_read(m);
LL i,j;
for(i=1;i<=m;i++){
_read(k);_read(a);_read(b);
if(k==1)_read(qust[i]);
fron[a].push_back(i);
bac[b+1].push_back(i);
num+=qust[i];
}
for(i=1;i<=n;i++){
for(j=0;j<fron[i].size();j++){
p=fron[i][j];
d= qust[p]?qust[p]: -num;
change(1,1,m);
}
for(j=0;j<bac[i].size();j++){
p=bac[i][j];
d=0;
change(1,1,m);
}
printf("%d ",tree[1].maxx);
}
}