题目
题解
据ddd说非常的恶心,于是找来做,最后之后抄题解才能调对
线段树需要维护许多值:当前最大值,当前加法标记,当前覆盖标记
历史最大值,历史最大的加法标记,历史覆盖标记。
pushdown函数比较长,其他的还好搞。
- 历史最大值:考虑这个区间的历史加法和历史覆盖,以及子树的当前最大值
- 历史加法:考虑这个区间的历史加法和子树的当前加法
- 历史覆盖:考虑这个区间的当前覆盖和子树的历史覆盖
值得注意的是如果子树当前没有覆盖,那么可以直接更新加法,否则应该把加法加到覆盖上
每到一层区间就直接下放标记,无论区间是否完全覆盖
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxn=100001;
const int inf=2*1e9;
int T,m,cnt,add[maxn<<2],a[maxn];
char opt;
struct Node{
int mx,add,cover;
}tree[maxn*20],his[maxn*20];//?
void pushup(int rt)
{
tree[rt].mx=max(tree[rt<<1].mx,tree[rt<<1|1].mx);
his[rt].mx=max(his[rt<<1].mx,his[rt<<1|1].mx);
}
void pushdown(int rt)
{
for (int i=0; i<=1; i++)
{
int son=rt<<1|i;//首先更新历史 tree[rt].cover写成 tree[son].cover
his[son].mx=max(his[son].mx,max(his[rt].cover,tree[son].mx+his[rt].add));//都是从父亲节点向下传标记
if (tree[son].cover!=-inf) his[son].cover=max(his[son].cover,tree[son].cover+his[rt].add);
else his[son].add=max(his[son].add,tree[son].add+his[rt].add);
if (tree[rt].add)//更新当前的值
{
if (tree[son].cover!=-inf) tree[son].cover+=tree[rt].add;
else tree[son].add+=tree[rt].add;
tree[son].mx+=tree[rt].add;
}
if (tree[rt].cover!=-inf)//注意-inf不要写成inf
{
tree[son].cover=tree[son].mx=tree[rt].cover;
tree[son].add=0;//覆盖之后当前的add要变为零
}
his[son].cover=max(his[son].cover,max(tree[son].cover,his[rt].cover));
his[son].add=max(his[son].add,tree[son].add);
}
tree[rt].add=his[rt].add=0;//当前的更新后重新考虑可否计入历史
tree[rt].cover=his[rt].cover=-inf;
}
void build_tree(int rt,int l,int r)
{
tree[rt].add=his[rt].add=0;
tree[rt].cover=his[rt].cover=-inf;
if (l==r)
{
tree[rt].mx=a[l];
his[rt].mx=a[l]; return;
}
int mid=(l+r)>>1;
build_tree(rt<<1,l,mid);
build_tree(rt<<1|1,mid+1,r);
pushup(rt);
}
void change(int rt,int L,int R,int C,int l,int r,bool ifhis)
{
if (l!=r) pushdown(rt);//每次都要pushdown
int mid=(l+r)>>1;
if (L<=l && r<=R)
{
if (!ifhis)
{
tree[rt].mx+=C; tree[rt].add+=C; his[rt].add+=C; return;
}
else tree[rt].mx=tree[rt].cover=his[rt].cover=C;
his[rt].mx=max(his[rt].mx,tree[rt].mx);
return;
}
if (L<=mid) change(rt<<1,L,R,C,l,mid,ifhis);
if (R>mid) change(rt<<1|1,L,R,C,mid+1,r,ifhis);
pushup(rt);
}
int ques(int rt,int L,int R,int l,int r,bool ifhis)
{
if (l!=r) pushdown(rt);
int ans=-inf;
if (L<=l && r<=R) return (ifhis?his[rt].mx:tree[rt].mx);
int mid=(l+r)>>1;
if (L<=mid) ans=max(ans,ques(rt<<1,L,R,l,mid,ifhis));
if (R>mid) ans=max(ans,ques(rt<<1|1,L,R,mid+1,r,ifhis));
return ans;
}
int main()
{
scanf("%d",&T);
for (int i=1; i<=T; i++) scanf("%d",&a[i]); scanf("%d",&m);
int n=T;
build_tree(1,1,n);
// for (int i=1; i<=n*2; i++) printf("%d: %d\n",i,tree[i].mx); return 0;
for (int i=1; i<=m; i++)
{
int x,y,z; opt=getchar();
while (opt!='Q'&&opt!='A'&&opt!='P'&&opt!='C') opt=getchar();
if (opt=='Q')
{
scanf("%d%d",&x,&y);
printf("%d\n",ques(1,x,y,1,n,0));
}
if (opt=='A')
{
scanf("%d%d",&x,&y);
printf("%d\n",ques(1,x,y,1,n,1));
}
if (opt=='P')
{
scanf("%d%d%d",&x,&y,&z);
change(1,x,y,z,1,n,0);
}
if (opt=='C')
{
scanf("%d%d%d",&x,&y,&z);
change(1,x,y,z,1,n,1);
}
}
return 0;
}
总结
看着zyf2000学姐的代码”肉眼调试”才改对,各种0和1,son和father,历史和现在都会搞混。迫切的提升代码能力
写代码要准,不然省选一轮GG。