题解 CF739C 【Alyona and towers】

· · 题解

线段树打标记

首先我们对整个数组做一次差分,这样可以更好的反应两个数之间的大小关系,以及可以把区间加变成单点加

这样就不用 pushdown 传 lazytag 了

转换为差分后就可以把问题转换一下:

[l,r] 之间最长的一个连续段使得:由一个连续的负数段和一个连续的正数段拼接起来

先说明节点信息意思:u 当前节点,lson 左子节点,rson 右子节点

$up_{u}$ 当前节点区间从最左开始往右的答案的长度 $down_{u}$ 当前节点区间从最右开始往左的答案的长度 转移: 显然,$ans_u=\max(ans_{lson},ans_{rson})

如果 lsonrson 区间的交点的两个位置中有 1 个是 0,或者 lson 的交点是负数而 rson 的交点是正数

那么说明 lsonrson 不可能把两个区间合并拼成一个新答案

所以,up_u=up_{lson},down_u=down_{rson}

如果可以合并:

那么可以更新一下答案: ans_u=\max(ans_{lson},ans_{rson},down_{lson}+up_{rson})

如果 up_{lson} 的长度恰好等于 lson 的区间长度,那么就可以把 up_{lson}up_{rson} 合并在一起变成 up_u

否则 up_u=up_{lson}

```cpp // This code writed by chtholly_micromaker(MicroMaker) #include <bits/stdc++.h> #define reg register #define int long long using namespace std; const int MaxN=300050; struct Node { int Ans; int l,r; int uplen,downlen; }tr[MaxN<<2]; template <class t> inline void read(t &s) { s=0; reg int f=1; reg char c=getchar(); while(!isdigit(c)) { if(c=='-') f=-1; c=getchar(); } while(isdigit(c)) s=(s<<3)+(s<<1)+(c^48),c=getchar(); s*=f; return; } #define lson (u<<1) #define rson (u<<1|1) int a[MaxN],inp[MaxN]; int n; inline int getsign(int x) { if(!x) return 0; return x>0?1:-1; } inline void checkmax(int &x,int y) { if(x<y) x=y; return; } inline void pushup(int u) { tr[u].Ans=max(tr[lson].Ans,tr[rson].Ans); checkmax(tr[u].Ans,max(tr[lson].uplen,tr[rson].downlen)); if(!a[tr[lson].r]||!a[tr[rson].l]|| getsign(a[tr[lson].r])<getsign(a[tr[rson].l])) { tr[u].uplen=tr[lson].uplen,tr[u].downlen=tr[rson].downlen; } else { checkmax(tr[u].Ans,tr[lson].downlen+tr[rson].uplen); if(tr[lson].uplen==tr[lson].r-tr[lson].l+1) tr[u].uplen=tr[lson].uplen+tr[rson].uplen; else tr[u].uplen=tr[lson].uplen; if(tr[rson].downlen==tr[rson].r-tr[rson].l+1) tr[u].downlen=tr[rson].downlen+tr[lson].downlen; else tr[u].downlen=tr[rson].downlen; } return; } inline void print() { for(int i=1;i<=20;++i) { puts("======================"); printf("Node [ %lld , %lld ]\n",tr[i].l,tr[i].r); printf("Ans %lld\n",tr[i].Ans); printf("up %lld down %lld\n",tr[i].uplen,tr[i].downlen); } puts("-=-=="); for(int i=1;i<=6;++i) printf("%d ",a[i]);puts(""); puts("======"); return; } inline void buildtr(int u,int l,int r) { tr[u].l=l;tr[u].r=r; if(l==r) { if(!a[l]) tr[u].Ans=tr[u].uplen=tr[u].downlen=0; else tr[u].uplen=tr[u].downlen=tr[u].Ans=1; return; } reg int mid=(l+r)>>1; buildtr(lson,l,mid); buildtr(rson,mid+1,r); pushup(u); return; } inline void modify(int u,int l,int r,int p,int k) { if(l==r) { a[l]+=k; if(!a[l]) tr[u].Ans=tr[u].uplen=tr[u].downlen=0; else tr[u].Ans=tr[u].uplen=tr[u].downlen=1; return; } reg int mid=(l+r)>>1; if(p<=mid) modify(lson,l,mid,p,k); else modify(rson,mid+1,r,p,k); pushup(u); return; } signed main(void) { // freopen("J.in","r",stdin); // freopen("J.out","w",stdout); int m; cin>>n; for(int i=1;i<=n;++i) read(inp[i]); if(n==1) { cin>>m; for(int i=1;i<=m;++i) puts("1"); return 0; } for(int i=1;i<n;++i) a[i]=inp[i+1]-inp[i]; buildtr(1,1,n-1); cin>>m; reg int l,r,d; for(int i=1;i<=m;++i) { // puts("O-oooooooooo AAAAE-A-A-I-A-U- JO-oooooooooooo AAE-O-A-A-U-U-A- E-eee-ee-eee AAAAE-A-E-I-E-A- JO-ooo-oo-oo-oo EEEEO-A-AAA-AAAA"); read(l);read(r);read(d); if(l!=1) modify(1,1,n-1,l-1,d); if(r!=n) modify(1,1,n-1,r,-d); // if(l!=1) // printf("modify %d +\n",l-1); // if(r!=n) // printf("modify %d -\n",r); printf("%lld\n",tr[1].Ans+1); // print(); } return 0; } ```