bzoj1558 [JSOI2009]等差数列

1558: [JSOI2009]等差数列

Time Limit: 5 Sec  Memory Limit: 64 MB
Submit: 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

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\n");
                continue;
            }
            node temp = query(1,1,n,s,t - 1);
            ll res = (t - s + 2) / 2;
            if (temp.sum == 0)
                printf("%lld\n",res);
            else
            {
                res = min(res,temp.sum + (temp.lsize + 1) / 2 + (temp.rsize + 1) / 2);
                printf("%lld\n",res);
            }
        }
    }

    return 0;
}

 

posted @ 2018-02-06 23:35  zbtrs  阅读(586)  评论(0编辑  收藏  举报