[JSOI2009]等差数列

链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1558

题解:

考虑这么用线段树进行维护,由于他有区间修改等差数列

很容易想到可以用差分数组来维护(这东西经常和数据结构用在一起)

那么每一次的区间修改就变成了单点修改

另外我们可以利用线段树来维护:

h---t区间等差数列个数,h----(t-1)区间等差数列个数,(h+1)---t区间等差数列个数

为了维护这三个值,要引入(h+1)-----(t-1)(这个转移非常巧妙)

为什么要维护这些呢,因为我们算一个就可以发现

当他们不是一个等差数列时,区间中有一个数是没有用的

由于进行了差分,等差数列其实就是差分数组的值相同

bzoj re了 并不知道为什么 对拍是对的

代码:

 

#include <bits/stdc++.h>
#define maxn 311111
#define mid (p[x].h+p[x].t)/2
using namespace std;
int n,m,a[maxn*2],b[maxn*2];
struct re
{
    int h,t,sum,sum1,sum2,sum3,lazy,hnum,tnum;
}p[maxn*4];
struct ree
{
    int sum,sum1,sum2;
};
void updata(int x)
{
    p[x].sum=min(p[x*2].sum2+p[x*2+1].sum,p[x*2].sum+p[x*2+1].sum1);
    p[x].sum1=min(p[x*2].sum3+p[x*2+1].sum,p[x*2].sum1+p[x*2+1].sum1);
    p[x].sum2=min(p[x*2].sum2+p[x*2+1].sum2,p[x*2].sum+p[x*2+1].sum3);
    p[x].sum3=min(p[x*2].sum3+p[x*2+1].sum2,p[x*2].sum1+p[x*2+1].sum3);
    if (p[x*2].tnum==p[x*2+1].hnum)
    {
        p[x].sum=min(p[x].sum,p[x*2].sum+p[x*2+1].sum-1);
        p[x].sum1=min(p[x].sum1,p[x*2].sum1+p[x*2+1].sum-1);
        p[x].sum2=min(p[x].sum2,p[x*2].sum+p[x*2+1].sum2-1);
        p[x].sum3=min(p[x].sum3,p[x*2].sum1+p[x*2+1].sum2-1);
    }
}
void build(int x,int h,int t)
{
    p[x].h=h; p[x].t=t; 
    p[x].hnum=b[p[x].h];
    p[x].tnum=b[p[x].t];
    if (p[x].h==p[x].t)
    {
        p[x].sum=p[x].sum1=p[x].sum2=1;p[x].sum3=0; return;
    }
    build(x*2,h,mid); build(x*2+1,mid+1,t);
    updata(x);
}
void down(int x)
{
  if (p[x].lazy)
  {
     p[x].hnum+=p[x].lazy;
     p[x].tnum+=p[x].lazy;
     if (p[x].h!=p[x].t)
     {
         p[x*2].lazy+=p[x].lazy;
         p[x*2+1].lazy+=p[x].lazy;
     }
     p[x].lazy=0;
  }
} 
void change(int x,int h,int t,int sum)
{
    down(x);
    if (p[x].h>t||p[x].t<h) return;
    if (h<=p[x].h&&p[x].t<=t)
    {
        p[x].lazy+=sum; down(x);
        return;
    }
    if (p[x].h<=t&&p[x].h>=h) p[x].hnum+=sum;
    if (p[x].t<=t&&p[x].t>=h) p[x].tnum+=sum;
    change(x*2,h,t,sum); 
    change(x*2+1,h,t,sum);
    updata(x);
}
re query(int x,int h,int t)
{
    down(x);
    re now;
    if (h<=p[x].h&&p[x].t<=t)
    { 
      now=p[x];
      return(now);
    }
    if (mid+1>t) return(query(x*2,h,t));
    if (mid<h) return(query(x*2+1,h,t));
    re a=query(x*2,h,t),b=query(x*2+1,h,t);
    now.sum=min(a.sum2+b.sum,a.sum+b.sum1);
    now.sum1=min(a.sum3+b.sum,a.sum1+b.sum1);
    now.sum2=min(a.sum2+b.sum2,a.sum+b.sum3);
    now.sum3=min(a.sum3+b.sum2,a.sum1+b.sum3);
    if (p[x*2].tnum==p[x*2+1].hnum)
    {
        now.sum=min(now.sum,a.sum+b.sum-1);
        now.sum1=min(now.sum1,a.sum1+b.sum-1);
        now.sum2=min(now.sum2,a.sum+b.sum2-1);
        now.sum3=min(now.sum3,a.sum1+b.sum2-1);
    }
    return(now);
}
int main()
{
    freopen("noip.in","r",stdin);
    freopen("noip.out","w",stdout);
    std::ios::sync_with_stdio(false);
    cin>>n;
    for (int i=1;i<=n;i++)
    {
        cin>>a[i];
        b[i-a]=a[i]-a[i-1];
    }
    build(1,1,n-1);
    //for (int i=1;i<=2*n;i++){cout<<p[i].h<<" "<<p[i].t<<" "<<p[i].sum<<endl;}
    cin>>m;
    char c;
    for (int i=1;i<=m;i++)
    {
        int a1,b1,c1,d1;
        cin>>c;
        if (c=='A') 
        {
            cin>>a1>>b1>>c1>>d1;
            change(1,a1,b1-1,d1);
            if (a1!=1) change(1,a1-1,a1-1,c1);
            change(1,b1,b1,-(c1+(b1-a1)*d1));
        }
        if (c=='B')
        {
            cin>>a1>>b1; re x;
            if (a1!=b1) x=query(1,a1,b1-1);
            else x.sum=1;
            cout<<x.sum<<endl;
        }
    }
}

 

转载于:https://www.cnblogs.com/yinwuxiao/p/8398473.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值