题目大意:给一个长度为n的数组a, 和一个长度为m的数组b,和更新次数q; 函数f(j)的意思是 , 求出最小的函数值,然后会有q次更新数组a, 每次更新一个区间,从l到r之间每个值加x。输出每次更新之后所有f的最小值。
解题思路:我们可以通过技巧获得没更新之前的每个函数值,具体看代码。我们看公式可以看出一个规律,我们更新数组a时,如果更新的个数是偶数,等于没更新(数组a的系数正负1交替出现,每两项x就会抵消),如果是奇数,并且是从奇数开始的(l为奇数),那么就是f加上x, 如果l时偶数,那就减去x。(因为偶数的系数时-1,那么最后一个没抵消的那个数的系数也是-1)。每次更新都是将所有的f加上或者减去x,因此我们没必要每次都更新,我们只需保存下来就可以,保存到一个值中cur中的话,那么我们只需找到所有f中与cur相差最小的那个数即可.(函数是绝对值)。用二分查找即可。
AC代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
int n, m, q;
long long F[100000];
long long B[100050];
long long lower_find(long long x)
{
int L =0, R = m-n;
while(R > L)
{
int mid = (R+L+1)/2;
if(F[mid] == x) return 0;
else if(F[mid] > x) R = mid-1;
else L = mid;
}
long long x1, x2;
x1 = abs(F[L]-x);
if(L < m-n)
x2 = abs(F[L+1]-x);
else x2 = 9223372036854775807;
return x1 < x2? x1 : x2;
}
int main()
{
scanf("%d%d%d", &n, &m, &q);
long long f = 1, a, b;
long long suma = 0,sumb = 0;
for(int i=1; i<=n; i++)
{
scanf("%lld", &a);
suma += f*a;
f = -f;
}
f = -1;
for(int i=1; i<=m; i++)
{
scanf("%lld", &B[i]);
sumb += B[i] * f;
f = -f;
if(i>=n)
{
int t = (i-n)%2 ? -1 : 1;
F[i-n] = suma + sumb * t;
sumb += B[i-n+1] * t;
}
}
sort(F, F+m-n+1);
int l, r;
long long x, cur = 0;
printf("%lld\n", lower_find(0));
for(int i=0; i<q; i++)
{
scanf("%d%d%lld", &l, &r, &x);
if((r-l)%2 == 0)
if(l%2 == 1) cur += x;
else cur -= x;
printf("%lld\n", lower_find(-cur));
}
return 0;
}