【题解】[COCI2020-2021#5] Sjeckanje

solution:

数据结构毒瘤题。

算法一:考虑不带修改。首先分析出一个性质,最优区间一定是单调区间。因为 f ( l , r ) ≤ m a x ( l , r ) − m i n ( l , r ) f(l,r)\leq max(l,r)-min(l,r) f(l,r)max(l,r)min(l,r) ,如果一个区间不是单调区间的话可以继续拆分直到都是单调区间,从而使得 f ( l , r ) ≥ m a x ( l , r ) − m i n ( l , r ) f(l,r)\geq max(l,r)-min(l,r) f(l,r)max(l,r)min(l,r) 。设 f [ i ] f[i] f[i] 表示前 i i i 个数贡献的最大值,可以 O ( n ) O(n) O(n) 求出,区间 ( l , r ] (l,r] (l,r] 的贡献就是 a [ r ] − a [ l + 1 ] a[r]-a[l+1] a[r]a[l+1] 。加上修改的话就暴力修改,时间复杂度 O ( n 2 ) O(n^2) O(n2)

算法二:考虑维护差分数组,将区间修改转化为单点修改。现在对于单调区间 [ l , r ] [l,r] [l,r] ,其贡献等于 ∑ i = l r c [ i ] \sum_{i=l}^rc[i] i=lrc[i] 。进一步地,总贡献等于 ∑ i = 1 n c [ i ] \sum_{i=1}^nc[i] i=1nc[i] ,所以我们只需要维护差分数组的和即可。规定 c [ 1 ] = 0 c[1]=0 c[1]=0 。当然实际计算是求的绝对值的和。

一个坑点在于, l e n = 1 len=1 len=1 的情况是没有贡献的,比较难判断。所以我们必须调整我们的策略:转化为在差分序列中选择一些数,使得选择的数中不存在相邻两个数,一个为正,一个为负。证明也比较容易,考虑 c [ i ] c[i] c[i] 能产生贡献当且仅当 [ i , i + 1 ] [i,i+1] [i,i+1] 在同一区间,如果有两个相邻的线段不能在同一集合的话就不能都产生贡献,反之则能。

现在我们可以用线段树维护了。 d p [ t ] [ 0 / 1 ] [ 0 / 1 ] dp[t][0/1][0/1] dp[t][0/1][0/1] 表示节点 t t t 的 左/右 端点 不选/选 时贡献的最大值。时间复杂度 O ( 2 4 ( n + q ) l o g n ) O(2^4(n+q)logn) O(24(n+q)logn)

#include<bits/stdc++.h> #define ll long long #define INF 0x3f3f3f3f using namespace std; const int mx=2e5+5; int n,q; ll dp[mx<<2][2][2]; ll a[mx],c[mx]; void PushUp(int p,int md) { for(int i=0;i<2;i++) { for(int j=0;j<2;j++) { dp[p][i][j]=-INF; for(int k=0;k<2;k++) { for(int l=0;l<2;l++) { if(k==1&&l==1&&(c[md]<0&&c[md+1]>0||c[md]>0&&c[md+1]<0)) continue; dp[p][i][j]=max(dp[p][i][j],dp[p<<1][i][k]+dp[p<<1|1][l][j]); } } } } } void update(int p,int l,int r,int x) { if(l==r) { dp[p][1][1]=abs(c[l]); return; } int mid=l+r>>1; if(x<=mid) update(p<<1,l,mid,x); else update(p<<1|1,mid+1,r,x); PushUp(p,mid); } ll query() { return max(max(dp[1][0][0],dp[1][0][1]),max(dp[1][1][0],dp[1][1][1])); } int main() { // freopen("data.in","r",stdin); scanf("%d%d",&n,&q); for(int i=1;i<=n;i++) scanf("%lld",&a[i]),c[i]=(i==1)?0:a[i]-a[i-1],update(1,1,n,i); for(int i=1;i<=q;i++) { int l,r,x; scanf("%d%d%d",&l,&r,&x); if(l!=1) { c[l]+=x; update(1,1,n,l); } if(r!=n) { c[r+1]-=x; update(1,1,n,r+1); } printf("%lld\n",query()); } }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530289.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(21)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示