分析
一开始想到差分+线段树,好像数据太大,拿不满分
于是看到了题解里某各路大佬都讲一个高端名词曰:二阶差分
何为二阶差分?就是对差分数组进行差分
乍一眼看去好像没用,但是手推一下会发现牛逼的地方
(图小,大佬轻喷)
我们发现,原数组要加上一个等差数列,而一阶差分只需区间均加,而二阶差分更恐怖,只需要修改4个数。。。
从图中不难推得:
设
l
,
r
,
s
,
e
如
题
意
,
且
公
差
为
d
设l,r,s,e如题意,且公差为d
设l,r,s,e如题意,且公差为d
则
对
于
二
阶
差
分
数
组
c
则对于二阶差分数组c
则对于二阶差分数组c
c
[
l
]
+
=
s
c[l]+=s
c[l]+=s
c [ l + 1 ] + = d − s c[l+1]+=d-s c[l+1]+=d−s
c [ r + 1 ] + = − d − e c[r+1]+=-d-e c[r+1]+=−d−e
c [ r + 2 ] + = e c[r+2]+=e c[r+2]+=e
于是这道题,就很简单了
先利用攻击数据构造二阶差分数组,然后输出答案时求两次前缀和(注意是前缀和,这是差分的性质)即可
code
#include<bits/stdc++.h>
using namespace std;
#define loop(i,start,end) for(int i=start;i<=end;i++)
#define clean(arry,num); memset(arry,num,sizeof(arry));
#define ll long long
#define max(a,b) ((a>b)?a:b)
ll n,m;
const int maxn=1e7+10;
ll a[maxn],b[maxn],c[maxn];
inline ll read()
{
ll ans=0;bool neg=false;char r=getchar();
while(r>'9'||r<'0'){if(r=='-')neg=true;r=getchar();}
while(r>='0'&&r<='9'){ans=ans*10+r-'0';r=getchar();}
return (neg)?-ans:ans;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("datain.txt","r",stdin);
#endif
n=read();m=read();
clean(a,0);clean(b,0);clean(c,0);
loop(i,1,m)
{
int l,r,s,e;l=read();r=read();s=read();e=read();
int d=(e-s)/(r-l);//方差
c[l]+=s;
c[l+1]+=d-s;
c[r+1]+=-e-d;
c[r+2]+=e;
}
ll res,maxx=-0x7f7f;
loop(i,1,n)
{
b[i]=b[i-1]+c[i];
a[i]=a[i-1]+b[i];//求前缀和
maxx=max(maxx,a[i]);
if(i!=1)res^=a[i];//按题意求异或和
else res=a[i];
}
printf("%lld %lld",res,maxx);
return 0;
}