等差数列嘛,就是公差相等嘛。求最长一段序列等差数列差不多就是求公差相等的序列最长的长度,但是,
注意
这里有一点点不一样,我们假设有三个连续的数公差为1,但是我们会说这串等差数列长度为4。而在区间左端点开始便右三个连续数公差为1则不一样,因为这样的等差效果没办法延申到左端点左方,那不在我们需要查询的区间内。
处理方法是查询从左端点右方一位开始至右端点结束,然后ans++。
然后就是简单的维护线段树的操作,维护等差数列,注意修改区间时
- 对区间右方的影响,二者间差值会改变,单点修改。
- 左端点单点修改+a
- p左方区间修改+k,p右方区间修改-k
pushup
然后就是线段树上区间合并的问题,算是本题最难写的部分——pushup:
我定义了树上每一个节点如下元素:左起点右起点,左起数值右起数值,左起序列长度右起序列长度,最长等差序列的公差,最长的长度,整个区间长度。
在每一次pushup都用左儿子和右儿子的属性更新当前节点,起点和起点数值,区间长度啥的都好更新。但是区间最大长度的更新则需要讨论,大致分以下三种情况:
- 在左儿子区间内有最长序列
- 在右儿子区间内有最长序列
- 若合并后的最长序列跨了左右区间,则更新,判断方式在于左儿子的右端点和右儿子的左端点相等时则代表可以合并,合并后比较即可。
这也影响了左起序列的长度的讨论,如果左儿子的右起序列覆盖了全线段,且此时正好被合并成为了最长序列,那就不是当前节点继承左儿子左起序列长度的说法了,应当直接合并后与最长序列长度相等才是。
右起序列同理。
query
至于query的写法,我们不妨把query定义成一个结构体node的类型,与树上节点类型相同,这样也更方便合并答案,至于合并方式直接复制粘贴pushup的写法改改即可,其他的操作与普通线段树无异。
AC代码如下(已去掉丢人的自己手动调试部分):
#include<bits/stdc++.h>
#define maxn 200005
#define maxm 200005
#define FOR(a, b, c) for(int a=b; a<=c; a++)
#define hrdg 1000000007
#define inf 2147483647
#define llinf 9223372036854775807
#define ll long long
#define pi acos(-1.0)
#define ls p<<1
#define rs p<<1|1
using namespace std;
inline int read()
{
char c=getchar();long long x=0,f=1;
while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
return x*f;
}
int n, m, ql, qr, a, k, p, type;
int num[maxn];
int tag[maxn<<2];
struct node{
int l, r, rval, lval, rlen, llen, maxv, maxl, len;
}tr[maxn<<2];
//左起点右起点,左起数值右起数值,左起序列长度右起序列长度,最长等差的差值,最长的长度,整个区间长度
void pushup(int p){
tr[p].l = tr[ls].l; tr[p].r = tr[rs].r; tr[p].len = tr[p].r - tr[p].l + 1;
tr[p].llen = tr[ls].llen; tr[p].lval = tr[ls].lval;
tr[p].rlen = tr[rs].rlen; tr[p].rval = tr[rs].rval;
if(tr[ls].maxl > tr[rs].maxl)
{
tr[p].maxl = tr[ls].maxl;
tr[p].maxv = tr[ls].maxv;
}
else
{
tr[p].maxl = tr[rs].maxl;
tr[p].maxv = tr[rs].maxv;
}
//更新左右儿子的最长序列到父亲节点
if(tr[ls].rval == tr[rs].lval)
{
if(tr[p].maxl < tr[ls].rlen + tr[rs].llen)
{
tr[p].maxl = tr[ls].rlen + tr[rs].llen;
tr[p].maxv = tr[ls].rval;
}//更新左右两儿子可能连起来的序列长度
if(tr[ls].rlen == tr[ls].len) //若左儿子的右起序列已经覆盖了整个左儿子节点的线段
tr[p].llen = tr[p].maxl;
if(tr[rs].llen == tr[rs].len) //右儿子同
tr[p].rlen = tr[p].maxl;
}
}
void build(int p, int l, int r){
tag[p] = 0;
if(l == r)
{
tr[p].l = tr[p].r = l; tr[p].len = 1;
tr[p].llen = 1; tr[p].rlen = 1; tr[p].maxl = 1;
tr[p].lval = tr[p].rval = tr[p].maxv = 0;
return;
}
int mid = (l+r) >> 1;
build(ls, l, mid);
build(rs, mid+1, r);
pushup(p);
}
void load(int p, int l, int r, int k){
tr[p].rval += k;
tr[p].lval += k;
tr[p].maxv += k;
tag[p] += k;
}
void pushdown(int p, int l, int r){
int mid = (l + r) >> 1;
load(ls, l, mid, tag[p]);
load(rs, mid+1, r, tag[p]);
tag[p] = 0;
}
void update(int nl, int nr, int l, int r, int p, int k){
if(nl > nr) return;
if(nl <= l && nr >= r)
{
load(p, l, r, k);
return;
}
pushdown(p, l, r);
int mid = (l + r) >> 1;
if(nl <= mid)
update(nl, nr, l, mid, ls, k);
if(nr >= mid+1)
update(nl, nr, mid+1, r, rs, k);
pushup(p);
}
node query(int nl, int nr, int l, int r, int p){ //直接将query定义成结构体node类型,返回值可以合并
node ret, lll, rrr;
if(nl > nr) return ret;
if(nl <= l && nr >= r)
return tr[p];
pushdown(p, l, r);
int mid = (l + r) >> 1;
if(nl <= mid)
lll = query(nl, nr, l, mid, ls);
if(nr >= mid + 1)
rrr = query(nl, nr, mid+1, r, rs);
if(nl <= mid && nr < mid + 1)
return lll;
if(nl > mid && nr >= mid + 1)
return rrr;
//接下来几行是合并lll和rrr的操作,是赋值粘贴pushup过来的
ret.l = lll.l; ret.r = rrr.r; ret.len = ret.r - ret.l + 1;
ret.llen = lll.llen; ret.lval = lll.lval;
ret.rlen = rrr.rlen; ret.rval = rrr.rval;
if(lll.maxl > rrr.maxl)
{
ret.maxl = lll.maxl;
ret.maxv = lll.maxv;
}
else
{
ret.maxl = rrr.maxl;
ret.maxv = rrr.maxv;
}
if(lll.rval == rrr.lval)
{
if(ret.maxl < lll.rlen + rrr.llen)
{
ret.maxl = lll.rlen + rrr.llen;
ret.maxv = lll.rval;
}
if(lll.rlen == lll.len)
ret.llen = ret.maxl;
if(rrr.llen == rrr.len)
ret.rlen = ret.maxl;
}
return ret;
}
int main()
{
n = read();
m = read();
build(1, 1, n);
while(m--)
{
type = read();
if(type == 0)
{
ql=read(); qr=read(); a=read(); k=read(); p=read();
update(ql, ql, 1, n, 1, a);
update(ql+1, p, 1, n, 1, k);
update(p+1, qr, 1, n, 1, -k);
if(qr != n)
update(qr+1, qr+1, 1, n, 1, -a-k*(2*p-ql-qr));
}
else
{
ql = read();
qr = read();
int ans = query(ql+1, qr, 1, n, 1).maxl; //从左端点右方开始查询,最后再加一
ans++;
printf("%d\n", ans);
}
}
return 0;
}
/*
5 3
0 1 5 2 2 2
0 3 5 4 2 4
1 1 5
*/
/*
6 2
0 1 6 5 1 4
1 1 2
*/