Codeforces Round #670 (Div. 2) D. Three Sequences 题解(差分+思维+构造)
题目链接
题目大意
给你一个长为n的数组a,要你构造一个非严格单调上升的数组b和一个非严格单调下降的数组c,使得\(b_i+c_i=a_i\) 要你使这两个数组b,c中最大的元素最小,还有q次修改(q<=1e5),每次修改使[l,r]上的所有元素加x。在线查询
题目思路
看到这个区间操作,在线查询,就能想到线段树qwq,结果居然是差分
假设现在已经确定了\(b[1]\)\(c[1]\)。
假设\(a[2]\)大于\(a[1]\)而\(b[2]+c[2]=a[2]\)
显然是想要b数组的每一个元素尽可能小,而c数组是非严格单调上升那么\(c[2]=c[1]\),则\(b[2]=b[2]+(a[2]-a[1])\)
同理可以得出结论
当\(a[i]>a[i-1]\)
\(b[i]=b[i-1]+(a[i]-a[i-1])\;\;c[i]=c[i-1]\)
当\(a[i]<a[i-1]\)
\(b[i]=b[i-1]\;\;c[i]=c[i-1]+(a[i]-a[i-1])\)
而\(ans=\max(b[1],c[n])\)
\(b[1]+c[1]=a[1]\)
\(b[n]=b[1]+s=\sum_{i=2}^{i=n}\max(a[i]-a[i-1],0)\)
上述两式可以推出
\(b[n]+c[1]=a[1]+s\)
则要使得ans最小,则要使得b[n]和c[1]尽可能相近,\(ans=(a[1]+2)/2\)
易错:注意负数/2,c语言中/2是向0靠近
代码
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#define fi first
#define se second
#define debug printf(" I am here\n");
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int maxn=1e5+5,inf=0x3f3f3f3f;
const double eps=1e-10;
int n,q;
ll a[maxn],b[maxn],res;
ll cal(){
ll ans=res+b[1];
if(ans>0){
return (ans+1)/2;
}else{
return ans/2;
}
}
signed main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
b[i]=a[i]-a[i-1];
if(i!=1&&b[i]>0){
res+=b[i];
}
}
printf("%lld\n",cal());
scanf("%d",&q);
for(int i=1,l,r,x;i<=q;i++){
scanf("%d%d%d",&l,&r,&x);
if(l!=1){
res=res-max(0ll,b[l])+max(0ll,b[l]+x);
}
b[l]+=x;
if(r!=n){
res=res-max(0ll,b[r+1])+max(0ll,b[r+1]-x);
}
b[r+1]-=x;
printf("%lld\n",cal());
}
return 0;
}
不摆烂了,写题