1558: [JSOI2009]等差数列
Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 777 Solved: 236
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
5
1
3
-1
-4
7
2
A 2 4 -1 5
B 1 5
1
3
-1
-4
7
2
A 2 4 -1 5
B 1 5
Sample Output
2
HINT
Source
分析:神犇眼中的套路题,蒟蒻眼中非常烦人的一道题!
首先可以肯定的是,这道题用线段树做.让维护等差序列,肯定不能维护真实的序列.既然涉及到差,一个常见的套路就是维护差分后的序列.差分后的序列每一位表示的元素实际上是由2个元素组成的,在修改的时候要格外注意,要单独修改两个端点的值.
第二问比较难处理.一个常见的错误想法是统计有多少段相等的数,考虑一个例子:差分后的序列为:1 2 3 4,其实最少能拆成2个等差数列(每两个拼成一个等差数列).这就要考虑怎么把不连续的数给拼起来,还要处理连续段的数.在pushup操作中维护.考虑两个区间合并的过程,两个区间内的答案在合并之前就已经统计好了,现在的任务就是统计两个区间连接处的答案.维护5个变量:lsize,rsize,sum,ls,rs,分别表示左边不相等的数的个数,右边不相等的数的个数,这一段中间最少能分成多少个等差数列(不包括lsize和rsize统计的两端的数),左右端点的数分别是什么.合并主要考虑大区间的sum,lsize和rsize的变化.容易发现如果左右子区间如果有一个sum = 0,那么lsize,rsize有可以穿过一个区间到达另一个区间,所以要特判处理sum = 0的情况,同时根据rs和ls是否相等来特殊处理sum.
当子区间的sum都不等于0的时候,lsize和rsize都是固定的,这时只需要维护sum就可以了.因为拼起来的数是不连续的,故两两一组拼.注意考虑两个端点相等的情况.
sum表示的具体区间范围容易理解错. 1 (2 2 3 3 2 3 3) 5 6 7,括号内部都是sum表示的区间,即使里面可能不是完全连续的,但是它外面的数一定是不连续的.如果右边再多一个7, 1 (2 2 3 3 2 3 3 5 6 7 7),表示范围也会随之改变,因为连续段在最右边又出现了一次.
最后统计答案有两种选择,要么是所有数两个两个拼在一起.要么是中间连续的数的段数+左右不连续的数的答案.
这道题没给完整的数据范围,数组不要开大了,否则MLE oj会告诉你0ms TLE,根本不知道为何为T......
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; const ll maxn = 500010; ll n,a[maxn],b[maxn],q; struct node { ll ls,rs,lsize,rsize,sum,tag,sizee; void init() { ls = rs = lsize = rsize = sum = tag = sizee = 0; } } e[maxn]; void pushdown(ll o) { if (e[o].tag) { e[o * 2].tag += e[o].tag; e[o * 2 + 1].tag += e[o].tag; e[o * 2].ls += e[o].tag; e[o * 2 + 1].ls += e[o].tag; e[o * 2].rs += e[o].tag; e[o * 2 + 1].rs += e[o].tag; e[o].tag = 0; } } node pushup(node a,node b) { bool flag = (a.rs == b.ls); node c; c.init(); c.ls = a.ls; c.rs = b.rs; c.sizee = a.sizee + b.sizee; c.sum = a.sum + b.sum; if (a.sum == 0 && b.sum == 0) { if (!flag) { c.lsize = a.sizee + b.sizee; c.rsize = a.sizee + b.sizee; } else { c.lsize = a.lsize - 1; c.rsize = b.rsize - 1; ++c.sum; } return c; } if (a.sum == 0) { c.rsize = b.rsize; if (!flag) c.lsize = a.sizee + b.lsize; else { c.lsize = a.lsize - 1; if (b.lsize > 0) c.sum += (b.lsize - 1) / 2 + 1; } return c; } if (b.sum == 0) { c.lsize = a.lsize; if (!flag) c.rsize = b.sizee + a.rsize; else { c.rsize = b.rsize - 1; if (a.rsize > 0) c.sum += (a.rsize - 1) / 2 + 1; } return c; } c.lsize = a.lsize; c.rsize = b.rsize; if (a.rsize == 0 && b.lsize == 0) { if (flag) c.sum--; return c; } if (a.rsize == 0) { if (flag) c.sum += (b.lsize - 1) / 2; else c.sum += b.lsize / 2; return c; } if (b.lsize == 0) { if (flag) c.sum += (a.rsize - 1) / 2; else c.sum += a.rsize / 2; return c; } ll minn = (a.rsize + b.lsize) / 2; if (flag) minn = min(minn,1 + (a.rsize - 1) / 2 + (b.lsize - 1) / 2); c.sum += minn; return c; } void build(ll o,ll l,ll r) { if (l == r) { e[o].init(); e[o].ls = e[o].rs = b[l]; e[o].lsize = e[o].rsize = 1; e[o].sizee = 1; return; } ll mid = (l + r) >> 1; build(o * 2,l,mid); build(o * 2 + 1,mid + 1,r); e[o] = pushup(e[o * 2],e[o * 2 + 1]); } void update1(ll o,ll l,ll r,ll pos,ll v) { if (l == r) { e[o].ls += v; e[o].rs += v; return; } pushdown(o); ll mid = (l + r) >> 1; if (pos <= mid) update1(o * 2,l,mid,pos,v); else update1(o * 2 + 1,mid + 1,r,pos,v); e[o] = pushup(e[o * 2],e[o * 2 + 1]); } void update2(ll o,ll l,ll r,ll x,ll y,ll v) { if (x <= l && r <= y) { e[o].ls += v; e[o].rs += v; e[o].tag += v; return; } pushdown(o); ll mid = (l + r) >> 1; if (x <= mid) update2(o * 2,l,mid,x,y,v); if (y > mid) update2(o * 2 + 1,mid + 1,r,x,y,v); e[o] = pushup(e[o * 2],e[o * 2 + 1]); } node query(ll o,ll l,ll r,ll x,ll y) { if (x <= l && r <= y) return e[o]; pushdown(o); ll mid = (l + r) >> 1; if (y <= mid) return query(o * 2,l,mid,x,y); else if (x > mid) return query(o * 2 + 1,mid + 1,r,x,y); else return pushup(query(o * 2,l,mid,x,mid),query(o * 2 + 1,mid + 1,r,mid + 1,y)); } int main() { scanf("%lld",&n); for (ll i = 1; i <= n; i++) scanf("%lld",&a[i]); for (ll i = 1; i < n; i++) b[i] = a[i + 1] - a[i]; n--; build(1,1,n); scanf("%lld",&q); while (q--) { char ch[2]; ll s,t,a,b; scanf("%s",ch); if (ch[0] == 'A') { scanf("%lld%lld%lld%lld",&s,&t,&a,&b); if (s != 1) update1(1,1,n,s - 1,a); if (t != n + 1) update1(1,1,n,t,-1 * ((t - s) * b + a)); if (s <= t - 1) update2(1,1,n,s,t - 1,b); } else { scanf("%lld%lld",&s,&t); if (s == t) { printf("1 "); continue; } node temp = query(1,1,n,s,t - 1); ll res = (t - s + 2) / 2; if (temp.sum == 0) printf("%lld ",res); else { res = min(res,temp.sum + (temp.lsize + 1) / 2 + (temp.rsize + 1) / 2); printf("%lld ",res); } } } return 0; }