# bzoj1558 [JSOI2009]等差数列

【题解】

# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm>
// # include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int M = 5e5 + 10;
const int mod = 1e9+7;

# define RG register
# define ST static

int n, a[M], b[M];

struct pa {
int s, ll, rr, sz;
// 连续（包括中间散的），左散，右散
long long l, r;
pa() {}
pa(int s, int ll, int rr, int sz, long long l, long long r) : s(s), ll(ll), rr(rr), sz(sz), l(l), r(r) {}
friend pa operator + (pa a, pa b) {
pa c; int f = (a.r == b.l);
c.s = a.s + b.s; c.sz = a.sz + b.sz;
c.l = a.l, c.r = b.r;
if(a.s == 0 && b.s == 0) {
if(!f) c.ll = c.rr = c.sz;
else {
c.ll = a.ll-1;
c.rr = b.rr-1;
++c.s;
}
return c;
}
if(a.s == 0) {
c.rr = b.rr;
if(!f) c.ll = a.sz + b.ll;
else {
c.ll = a.ll-1;
if(b.ll > 0) c.s += (b.ll-1)/2 + 1;
}
return c;
}
if(b.s == 0) {
c.ll = a.ll;
if(!f) c.rr = a.rr + b.sz;
else {
c.rr = b.rr-1;
if(a.rr > 0) c.s += (a.rr-1)/2 + 1;
}
return c;
}

c.ll = a.ll, c.rr = b.rr;

if(a.rr == 0 && b.ll == 0) {
if(f) --c.s;
return c;
}
if(a.rr == 0) {
if(f) c.s += (b.ll-1)/2;
else c.s += b.ll/2;
return c;
}
if(b.ll == 0) {
if(f) c.s += (a.rr-1)/2;
else c.s += a.rr/2;
return c;
}

int d = (a.rr + b.ll)/2;
if(f) d = min(d, 1 + (a.rr-1)/2 + (b.ll-1)/2);

c.s += d;

return c;
}
};

namespace SMT {
pa w[M];
ll tag[M];
# define ls (x<<1)
# define rs (x<<1|1)
inline void up(int x) {
if(!x) return;
if(!rs) {w[x] = w[ls]; return;}
if(!ls) {w[x] = w[rs]; return;}
w[x] = w[ls] + w[rs];
}
inline void pushtag(int x, ll d) {
w[x].l += d, w[x].r += d;
tag[x] += d;
}
inline void down(int x) {
if(!x) return;
if(!tag[x]) return;
pushtag(ls, tag[x]);
pushtag(rs, tag[x]);
tag[x] = 0;
}
inline void build(int x, int l, int r) {
tag[x] = 0;
if(l == r) {
w[x] = pa(0, 1, 1, 1, b[l], b[l]);
return ;
}
int mid = l+r>>1;
build(ls, l, mid);
build(rs, mid+1, r);
up(x);
}
inline void edt(int x, int l, int r, int L, int R, ll d) {
if(L <= l && r <= R) {
pushtag(x, d);
return ;
}
down(x);
int mid = l+r>>1;
if(L <= mid) edt(ls, l, mid, L, R, d);
if(R > mid) edt(rs, mid+1, r, L, R, d);
up(x);
}
inline pa query(int x, int l, int r, int L, int R) {
if(L <= l && r <= R) return w[x];
down(x);
int mid = l+r>>1;
if(R <= mid) return query(ls, l, mid, L, R);
else if(L > mid) return query(rs, mid+1, r, L, R);
else return query(ls, l, mid, L, mid) + query(rs, mid+1, r, mid+1, R);
}
inline void debug(int x, int l, int r) {
printf("x=%d, l=%d, r=%d:  sum = %d, size = %d, left = %d, right = %d, lnum = %lld, rnum = %lld\n", x, l, r, w[x].s, w[x].sz, w[x].ll, w[x].rr, w[x].l, w[x].r);
if(l==r) return;
down(x);
int mid = l+r>>1;
debug(ls, l, mid);
debug(rs, mid+1, r);
}
}

int main() {
int Q, l, r, a1, d;
char opt[23];
pa t;
cin >> n;
for (int i=1; i<=n; ++i) scanf("%d", a+i);
for (int i=1; i<n; ++i) b[i] = a[i+1] - a[i];
//    for (int i=1; i<n; ++i) printf("%d ", b[i]); puts("");
cin >> Q;
if(n == 1) {
while(Q--) {
scanf("%s", opt);
if(opt[0] == 'A') scanf("%*d%*d%*d%*d");
if(opt[0] == 'B') {scanf("%*d%*d"); puts("1");}
}
return 0;
}
SMT::build(1, 1, n-1);
//    SMT::debug(1, 1, n-1);
while(Q--) {
scanf("%s", opt);
if(opt[0] == 'A') {
scanf("%d%d%d%d", &l, &r, &a1, &d);
if(l != 1) SMT::edt(1, 1, n-1, l-1, l-1, a1);
if(l <= r-1) SMT::edt(1, 1, n-1, l, r-1, d);
if(r != n) SMT::edt(1, 1, n-1, r, r, -1ll * (r-l)*d - a1);
}
if(opt[0] == 'B') {
scanf("%d%d", &l, &r);
if(l == r) puts("1");
else {
t = SMT::query(1, 1, n-1, l, r-1);
int ans = (r-l+1+1)/2;
if(t.s == 0) printf("%d\n", ans);
else {
ans = min(ans, t.s + (t.ll+1)/2 + (t.rr+1)/2);
printf("%d\n", ans);
}
}
}
//        SMT::debug(1, 1, n-1);
}
return 0;
}
View Code

n=6, a[]={1,2,4,7,11,16}

1. 区间中的等差数列段数。

2. 区间左边剩下的零散数的个数，以及右边剩下的零散数的个数

3. 区间左边的数是什么，区间右边的数是什么

4. 区间大小。

1. 要么是(r-l+1+1)/2（r-l+1为区间长度，这种分法是两个数两个数分）

2. 要么是询问出来的区间中的等差数列段数加上区间左边剩下的零散数的个数，以及右边剩下的零散数的个数按照1中方法分成等差数列的个数。

 1 struct pa {
2     int s, ll, rr, sz;
3     // 连续（包括中间散的），左散，右散
4     long long l, r;
5     pa() {}
6     pa(int s, int ll, int rr, int sz, long long l, long long r) : s(s), ll(ll), rr(rr), sz(sz), l(l), r(r) {}
7     friend pa operator + (pa a, pa b) {
8         pa c; int f = (a.r == b.l);
9         c.s = a.s + b.s; c.sz = a.sz + b.sz;
10         c.l = a.l, c.r = b.r;
11         if(a.s == 0 && b.s == 0) {
12             if(!f) c.ll = c.rr = c.sz;
13             else {
14                 c.ll = a.ll-1;
15                 c.rr = b.rr-1;
16                 ++c.s;
17             }
18             return c;
19         }
20         if(a.s == 0) {
21             c.rr = b.rr;
22             if(!f) c.ll = a.sz + b.ll;
23             else {
24                 c.ll = a.ll-1;
25                 if(b.ll > 0) c.s += (b.ll-1)/2 + 1;
26             }
27             return c;
28         }
29         if(b.s == 0) {
30             c.ll = a.ll;
31             if(!f) c.rr = a.rr + b.sz;
32             else {
33                 c.rr = b.rr-1;
34                 if(a.rr > 0) c.s += (a.rr-1)/2 + 1;
35             }
36             return c;
37         }
38
39         c.ll = a.ll, c.rr = b.rr;
40
41         if(a.rr == 0 && b.ll == 0) {
42             if(f) --c.s;
43             return c;
44         }
45         if(a.rr == 0) {
46             if(f) c.s += (b.ll-1)/2;
47             else c.s += b.ll/2;
48             return c;
49         }
50         if(b.ll == 0) {
51             if(f) c.s += (a.rr-1)/2;
52             else c.s += a.rr/2;
53             return c;
54         }
55
56         int d = (a.rr + b.ll)/2;
57         if(f) d = min(d, 1 + (a.rr-1)/2 + (b.ll-1)/2);
58
59         c.s += d;
60
61         return c;
62     }
63 };

posted @ 2017-06-01 11:04  Galaxies  阅读(821)  评论(0编辑  收藏  举报