zoukankan      html  css  js  c++  java
  • [JSOI2009]等差数列

    第一篇博客哒

    题目链接

    首先看到区间加等差数列我们可以首先想到使用差分数组

    就是记一个(b_i)=(a_{i+1})-(a_i)

    然后每次修改(a_l)(a_r)就只用将(b_{l-1}),(b_r)单点修改,(b_l)(b_{r-1})区间修改就可以了

    区间修改?我们首先想到了线段树

    线段树可以维护是否为等差数列吗???

    可以!

    每个结点维护上啥线段树必要的l,r,lazy标记什么的在多维护一个结构体val

    val 里面有什么呢?

    首先为了下面转移方便维护区间最左边lv,最右边的点的值rv

    然后维护ls,rs,nos,lrs

    分别表示([l,r)) ((l,r]) ((l,r)) ([l,r]) 区间的答案

    开始转移 我们考虑合并区间a,和区间b

    考虑(a_r) (b_l)这两个点

    有以下三种情况

    1.可以直接合并。如果两者的差值相同,则可以将原来的等差数列合并为一个
    2.a两侧都不选,左边的右端点作为一个等差数列的首项(所以不选),b就要选择左端点(因为他不用考虑做首项了)
    3.a选右端点,b的左端点作为一个等差数列的首项,所以b两边都不选

    如何操作,看代码吧

    #include<cstdio>
    inline int min(int a,int b){return a<b?a:b;}
    inline int m(int a,int b,int c ){return min(a,min(b,c));}
    using namespace std;
    const int N=400100;
    int a[N],n,q,x,y,s,b;
    char opt[10];
    struct val{int ls,lv,rv,rs,lrs,nos;};
    struct seg{int l,r,tag;val s;}t[N];
    template<class T>void read(T &x){
        x=0;int f=0;char ch=getchar();
        while(ch<'0'||ch>'9') {f|=(ch=='-');ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        x=f?-x:x;
    }
    val operator+(val l,val r)
    {
      val x;
      x.lv=l.lv,
      x.rv=r.rv;
      x.ls=m(l.lrs+r.ls-(l.rv==r.lv),l.lrs+r.nos,l.ls+r.ls);
      x.rs=m(l.rs+r.lrs-(l.rv==r.lv),l.rs+r.rs,l.nos+r.lrs);
      x.nos=m(l.rs+r.ls-(l.rv==r.lv),l.rs+r.nos,l.nos+r.ls);
      x.lrs=m(l.lrs+r.lrs-(l.rv==r.lv),l.lrs+r.rs,l.ls+r.lrs);
      return x;
    }
    inline void build(int pos,int l,int r)
    {
      t[pos].l=l,t[pos].r=r;
      if(l==r)
      {
        t[pos].s.lv=t[pos].s.rv=a[l];
        t[pos].s.ls=t[pos].s.rs=t[pos].s.lrs=1;return ;
      }
      int mid=l+r>>1;
      build(pos<<1,l,mid);
      build(pos<<1|1,mid+1,r);
      t[pos].s=t[pos<<1].s+t[pos<<1|1].s;
    }
    inline void pushdown(int pos)
    {
      int tag=t[pos].tag;
      if(tag)
      {
        t[pos].tag=0;
        t[pos<<1].s.lv+=tag,t[pos<<1|1].s.lv+=tag;
        t[pos<<1].tag+=tag, t[pos<<1|1].tag+=tag;
        t[pos<<1].s.rv+=tag,t[pos<<1|1].s.rv+=tag;
      }
    }
    inline void modify(int pos,int x,int y,int w)
    {
      if(x<=t[pos].l&&t[pos].r<=y)
      {
        t[pos].tag+=w,t[pos].s.lv+=w,t[pos].s.rv+=w;
        return ;
      }
      pushdown(pos);
      int mid=t[pos].l+t[pos].r>>1;
      if(y<=mid) modify(pos<<1,x,y,w);
      else if(x>mid) modify(pos<<1|1,x,y,w);
      else modify(pos<<1,x,y,w),modify(pos<<1|1,x,y,w);
      t[pos].s=t[pos<<1].s+t[pos<<1|1].s;
    }
    inline val query(int pos,int x,int y)
    {
      if(x<=t[pos].l&&t[pos].r<=y) return t[pos].s;
      int mid=t[pos].l+t[pos].r>>1;
      pushdown(pos);
      if(y<=mid) return query(pos<<1,x,y);
      if(x>mid) return query(pos<<1|1,x,y);
      return query(pos<<1,x,y)+query(pos<<1|1,x,y);
    }
    
    int main()
    {
      read(n);
      for(int i=1;i<=n;i++) read(a[i]);
      for(int i=1;i<n;i++) a[i]=a[i+1]-a[i];
      build(1,1,n-1);
      read(q);
      for(int i=1;i<=q;i++)
      {
        scanf("%s",opt);
        if(opt[0]=='A')
        {
          read(x),read(y),read(s),read(b);
          if(x!=1) modify(1,x-1,x-1,s);
          if(x!=y) modify(1,x,y-1,b);
          if(y!=n) modify(1,y,y,-((y-x)*b+s));
        }
        else
        {
          read(x),read(y);
          if(x==y) puts("1");
          else printf("%d
    ",query(1,x,y-1).lrs);
        }
      }
    }
    
    
    
  • 相关阅读:
    模拟登陆江西理工大学教务系统
    python3爬虫 -----华东交大校园新闻爬取与数据分析
    以selenium模拟登陆12306
    PAT (Basic Level) Practice (中文)1076 Wifi密码 (15 分)
    PAT (Basic Level) Practice (中文)1047 编程团体赛 (20 分)
    PAT (Basic Level) Practice (中文)1029 旧键盘 (20 分)
    PAT (Basic Level) Practice (中文)1016 部分A+B (15 分)
    PAT (Basic Level) Practice (中文)1031 查验身份证 (15 分)
    PAT (Basic Level) Practice (中文)1041 考试座位号 (15 分)
    PAT (Basic Level) Practice (中文)1037 在霍格沃茨找零钱 (20 分)
  • 原文地址:https://www.cnblogs.com/Phoenix41/p/12248244.html
Copyright © 2011-2022 走看看