[JSOI2009]等差数列
[JSOI2009]等差数列
https://ac.nowcoder.com/acm/problem/20177
思路
对于这题,首先要知道维护一些什么东西.
我们都知道区间加个等差数列,假如维护单点求和的话,直接维护公差即可.因为区间加一个等差数列只需要两次单点修改和一次区间修改即可.
对于这题,我们很容易想到维护公差.但是对于查询操作维护公差是远远不够的.每次是询问你区间中有多少个等差数列.对于这个查询啊,我们假如线段树维护的是公差的话,我们很容易想到公差相等的一定是属于一个等差数列,但是!我们维护的是公差对吧,公差不相等它也可能是一个等差数列.
列如:
原数组[1 2 3 6 11 16]. 公差数组[1 1 3 5 5].
显然这个答案是2的.
所以我们需要维护的信息需要加一些.
我们不妨设为cl,cr,clr,nlr,lval,rval. 分别表示为[l,r),(l,r],[l,r],(l,r)的答案最小值.左端点的价值,右端点的价值.
然后转移下这些信息就是答案了~这题就解决了...
这里写下这个的转移.
tr[u].lval=tr[u<<1].lval,tr[u].rval=tr[u<<1|1].rval; tr[u].cl=tr[u<<1].clr+tr[u<<1|1].cl-(tr[u<<1].rval==tr[u<<1|1].lval); tr[u].cl=min(tr[u].cl,min(tr[u<<1].cl+tr[u<<1|1].cl,tr[u<<1].clr+tr[u<<1|1].nlr)); tr[u].cr=tr[u<<1].cr+tr[u<<1|1].clr-(tr[u<<1].rval==tr[u<<1|1].lval); tr[u].cr=min(tr[u].cr,min(tr[u<<1].cr+tr[u<<1|1].cr,tr[u<<1].nlr+tr[u<<1|1].clr)); tr[u].clr=tr[u<<1].clr+tr[u<<1|1].clr-(tr[u<<1].rval==tr[u<<1|1].lval); tr[u].clr=min(tr[u].clr,min(tr[u<<1].clr+tr[u<<1|1].cr,tr[u<<1].cl+tr[u<<1|1].clr)); tr[u].nlr=tr[u<<1].cr+tr[u<<1|1].cl-(tr[u<<1].rval==tr[u<<1|1].lval); tr[u].nlr=min(tr[u].nlr,min(tr[u<<1].nlr+tr[u<<1|1].cl,tr[u<<1].cr+tr[u<<1|1].nlr));
还挺多的...
代码
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e5+5; struct Tree{ ll l,r,lval,rval,cl,cr,clr,nlr,lazy; }tr[N<<2]; ll v[N]; void pushup(ll u) { tr[u].lval=tr[u<<1].lval,tr[u].rval=tr[u<<1|1].rval; tr[u].cl=tr[u<<1].clr+tr[u<<1|1].cl-(tr[u<<1].rval==tr[u<<1|1].lval); tr[u].cl=min(tr[u].cl,min(tr[u<<1].cl+tr[u<<1|1].cl,tr[u<<1].clr+tr[u<<1|1].nlr)); tr[u].cr=tr[u<<1].cr+tr[u<<1|1].clr-(tr[u<<1].rval==tr[u<<1|1].lval); tr[u].cr=min(tr[u].cr,min(tr[u<<1].cr+tr[u<<1|1].cr,tr[u<<1].nlr+tr[u<<1|1].clr)); tr[u].clr=tr[u<<1].clr+tr[u<<1|1].clr-(tr[u<<1].rval==tr[u<<1|1].lval); tr[u].clr=min(tr[u].clr,min(tr[u<<1].clr+tr[u<<1|1].cr,tr[u<<1].cl+tr[u<<1|1].clr)); tr[u].nlr=tr[u<<1].cr+tr[u<<1|1].cl-(tr[u<<1].rval==tr[u<<1|1].lval); tr[u].nlr=min(tr[u].nlr,min(tr[u<<1].nlr+tr[u<<1|1].cl,tr[u<<1].cr+tr[u<<1|1].nlr)); } void pushdown(ll u) { if(tr[u].lazy) { tr[u<<1].lazy+=tr[u].lazy; tr[u<<1|1].lazy+=tr[u].lazy; tr[u<<1].lval+=tr[u].lazy; tr[u<<1|1].lval+=tr[u].lazy; tr[u<<1].rval+=tr[u].lazy; tr[u<<1|1].rval+=tr[u].lazy; tr[u].lazy=0; } } void add(ll u,ll l,ll r,ll val) { if(l>tr[u].r||r<tr[u].l) return; if(l<=tr[u].l&&r>=tr[u].r) { tr[u].lazy+=val; tr[u].lval+=val; tr[u].rval+=val; return; } pushdown(u); add(u<<1,l,r,val); add(u<<1|1,l,r,val); pushup(u); } Tree query(ll u,ll l,ll r); Tree marge(ll u,ll l,ll r) { Tree res; Tree L=query(u<<1,l,r); Tree R=query(u<<1|1,l,r); res.l=L.l,res.r=R.r,res.lval=L.lval,res.rval=R.rval; res.cl=L.clr+R.cl-(L.rval==R.lval); res.cl=min(res.cl,min(L.cl+R.cl,L.clr+R.nlr)); res.cr=L.cr+R.clr-(L.rval==R.lval); res.cr=min(res.cr,min(L.cr+R.cr,L.nlr+R.clr)); res.clr=L.clr+R.clr-(L.rval==R.lval); res.clr=min(res.clr,min(L.clr+R.cr,L.cl+R.clr)); res.nlr=L.cr+R.cl-(L.rval==R.lval); res.nlr=min(res.nlr,min(L.nlr+R.cl,L.cr+R.nlr)); return res; } Tree query(ll u,ll l,ll r) { if(l<=tr[u].l&&r>=tr[u].r) return tr[u]; pushdown(u); ll mid=(tr[u].l+tr[u].r)>>1; if(r<=mid) return query(u<<1,l,r); if(l>mid) return query(u<<1|1,l,r); return marge(u,l,r); } void build(ll u,ll l,ll r) { tr[u].l=l,tr[u].r=r; if(l==r) { tr[u].lval=tr[u].rval=v[l]; tr[u].cl=tr[u].cr=tr[u].clr=1; return; } int mid=(l+r)>>1; build(u<<1,l,mid); build(u<<1|1,mid+1,r); pushup(u); } int main() { ll n; scanf("%lld",&n); for(int i=1;i<=n;i++) scanf("%lld",&v[i]); for(int i=1;i<n;i++) v[i]=v[i+1]-v[i]; build(1,1,n-1); ll Q; scanf("%lld",&Q); while(Q--) { char c; cin>>c; if(c=='A') { ll s,t,a,b; scanf("%lld%lld%lld%lld",&s,&t,&a,&b); //s-1 [s,t-1] t if(s!=1) add(1,s-1,s-1,a); if(t!=n) add(1,t,t,-(a+b*(t-s))); if(s!=t) add(1,s,t-1,b); } else { ll s,t; scanf("%lld%lld",&s,&t); if(s==t) puts("1"); else printf("%lld\n",query(1,s,t-1).clr); } } return 0; }
lpt的小屋 文章被收录于专栏
我想要一份甜甜的爱情