题目描述:
给出一串序列
有两个操作
A S T a b 表示 S T区间内每个数 Vi 变成 Vi+(i-s)*b+a
B S T 表示 查询 S T 区间内的数最少可以划分为几段等差数列
题目分析:
线段树玩出花系列~
首先,对于等差数列
我们其实并不需要真实的值
而是前后两个元素的差值
一段 等差数列 差分之后 值一定是相等的
那么我们就把序列差分 Val[i]=Val[i+1]-Val[i]
对 差分值建立线段树
对于操作 1
差分之后等价于
在 S 的位置 +a
而在 T -((a+b*(t-s))
在 S - T-1的位置加上 b
如何统计答案呢
对于每个线段树区间维护 l,r s[0],s[1],s[2],s[3]
l,r 分别表示区间右端和左端的值
s[0] 左右端点都不选的划分数,s[1] 选上左端点的划分数,s[2] 选上右端点的划分数,s[3] 左右都选的划分数
以s[0]为例 s[0]=min(lc->s[2]+rc->s[1]-(lc->r==rc->l), lc->s[0]+rc->s[1], lc->s[2]+rc->s[0])
其他依次类推
注意特判和细节!
题目链接:
Ac 代码:
#include <cstdio>
#include <iostream>
#define il inline
#define lson (o<<1)
#define rson (o<<1)|1
il int read()
{
int x=0,w=1;
char ch=0;
while(ch<'0'||ch>'9')
{
if(ch=='-') w=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<3)+(x<<1)+ch-'0';
ch=getchar();
}
return x*w;
}
const int maxm=110005;
il int min(int a,int b,int c)
{
return std::min(std::min(a,b),c);
}
struct node{
int l,r,s[4];//s[0] 左右端点都不选的划分数,s[1] 选上左端点的划分数,s[2] 选上右端点的划分数,s[3] 左右都选的划分数
node operator + (const node &a) const
{
node tmp;
tmp.l=l; tmp.r=a.r;
tmp.s[0]=min(s[2]+a.s[1]-(r==a.l),s[0]+a.s[1],s[2]+a.s[0]);
tmp.s[1]=min(s[3]+a.s[1]-(r==a.l),s[1]+a.s[1],s[3]+a.s[0]);
tmp.s[2]=min(s[2]+a.s[3]-(r==a.l),s[0]+a.s[3],s[2]+a.s[2]);
tmp.s[3]=min(s[3]+a.s[3]-(r==a.l),s[1]+a.s[3],s[3]+a.s[2]);
return tmp;
}
};
struct tree{
int add;
node t;
}st[maxm<<2];
int val[maxm],n,q;
namespace seg{
il node xclear()
{
node x;
x.l=x.r=x.s[0]=x.s[1]=x.s[2]=x.s[3]=0;
return x;
}
void build(int o,int l,int r)
{
if(l==r)
{
st[o].t.s[0]=0;
st[o].t.s[1]=st[o].t.s[2]=st[o].t.s[3]=1;
st[o].t.l=st[o].t.r=val[l];
st[o].add=0;
return;
}
int mid=(l+r)>>1;
build(lson,l,mid),build(rson,mid+1,r);
st[o].add=0;
st[o].t=st[(o<<1)].t+st[(o<<1)|1].t;
}
il void col(int o,int adx)
{
st[o].add+=adx;
st[o].t.l+=adx,st[o].t.r+=adx;
}
il void pushdown(int o)
{
if(st[o].add)
{
col(lson,st[o].add);
col(rson,st[o].add);
st[o].add=0;
}
}
void change(int o,int l,int r,int ql,int qr,int num)
{
if(ql<=l&&r<=qr)
{
col(o,num);
return;
}
pushdown(o);
int mid=(l+r)>>1;
if (ql<=mid) change(lson,l,mid,ql,qr,num);
if (qr>mid) change(rson,mid+1,r,ql,qr,num);
st[o].t=st[(o<<1)].t+st[(o<<1)|1].t;
}
node ask(int o,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr) return st[o].t;
pushdown(o);
int mid=(l+r)>>1;
if(qr<=mid) return ask(lson,l,mid,ql,qr);
if(ql>mid) return ask(rson,mid+1,r,ql,qr);
return ask(lson,l,mid,ql,qr)+ask(rson,mid+1,r,ql,qr);
}
}
int main()
{
//freopen("test.in","r",stdin);
n=read();
for(int i=1;i<=n;i++) val[i]=read();
for(int i=1;i<n;i++) val[i]=val[i+1]-val[i];
//for(int i=1;i<n;i++) printf("%d ",val[i]);
seg::build(1,1,n-1);
q=read();
while(q--)
{
char s[10];
scanf("%s",s);
if(s[0]=='A')
{
int u=read(),v=read(),a=read(),b=read();
if(u!=1) seg::change(1,1,n-1,u-1,u-1,a);
if(v!=n) seg::change(1,1,n-1,v,v,-(a+b*(v-u)));
if(u!=v) seg::change(1,1,n-1,u,v-1,b);
}
else
{
int u=read(),v=read();
if(u==v) printf("1\n");
else printf("%d\n",seg::ask(1,1,n-1,u,v-1).s[3]);
}
}
return 0;
}