• 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
    ");
                    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;
    }
  • 相关阅读:
    P1613 跑路
    数据挖掘-聚类分析(Python实现K-Means算法)
    使用scikit-learn 估计器分类
    数据挖掘-集成学习
    数据挖掘-关联分析 Apriori算法和FP-growth 算法
    scikit-learn 中常用的评估模型
    数据挖掘---支持向量机(SVM)
    数据挖掘-KNN-K最近邻算法
    数据挖掘-决策树
    数据挖掘-逻辑Logistic回归
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8424737.html
Copyright © 2020-2023  润新知