• [差分][线段树] Luogu P4243 等差数列


    题目描述

    为了检验学生的掌握情况,jyy布置了一道习题:给定一个长度为NN(1 leq N leq 100,0001N100,000)的数列,初始时第ii个数为v_iviv_ivi是整数,-100,000 leq v_i leq 100,000100,000vi100,000),学生们要按照jyy的给出的操作步骤来改变数列中的某些项的值。操作步骤的具体形式为:A s t a b (s, t, a, bs,t,a,b均为整数,1 leq s leq t leq N1stN,-100,000 leq a, b leq 100,000100,000a,b100,000),它表示,在序列的[s, t][s,t]区间上加上初值为aa,步长为bb的等差数列。即v_ivi变为v_i + a + b imes (i - s)vi+a+b×(is)(对于s leq i leq tsit)。

    在焦头烂额地计算之余,可怜的火星学生们还得随时回答jyy提出的问题。问题形式为:B s ts, ts,t均为整数,1 leq s leq t leq N1stN),表示jyy询问当前序列的[s, t][s,t]区间最少能划分成几段,使得每一段都是等差数列。比如说1 2 3 5 7最少能划分成22段,一段是1 2 3,另一段是5 7。询问是需要同学们计算出答案后,作为作业交上来的。

    虽然操作数加问题数总共只有QQ(1 leq Q leq 100,0001Q100,000)个,jyy还是觉得这个题很无聊很麻烦。于是他想让你帮他算一份标准答案。

    题解

    • 线段树维护差分数组,将修改操作变成区间加和单点修改,然后用线段树合并,维护区间左右区间是否取就OK了

    代码

     1 #include <iostream>
     2 #include <cstdio>
     3 #define N 100010
     4 using namespace std;
     5 int n,q,s[N];
     6 char op[4];
     7 void th(int&x,int y){if(y<x) x=y;}
     8 struct data
     9 {
    10     int s[4],l,r;
    11     data operator + (data y)
    12     {
    13         data c; c.l=l,c.r=y.r;
    14         c.s[0]=s[2]+y.s[1]-(r==y.l),th(c.s[0],s[0]+y.s[1]);th(c.s[0],s[2]+y.s[0]);
    15         c.s[1]=s[3]+y.s[1]-(r==y.l),th(c.s[1],s[1]+y.s[1]);th(c.s[1],s[3]+y.s[0]);
    16         c.s[2]=s[2]+y.s[3]-(r==y.l),th(c.s[2],s[2]+y.s[2]);th(c.s[2],s[0]+y.s[3]);
    17         c.s[3]=s[3]+y.s[3]-(r==y.l),th(c.s[3],s[3]+y.s[2]);th(c.s[3],s[1]+y.s[3]); 
    18         return c;
    19     }
    20 };struct node{ int l,r,val;data x; }t[N*4];
    21 void pushdown(int d)
    22 {
    23     int l=d*2,r=d*2+1;
    24     t[l].val+=t[d].val,t[r].val+=t[d].val,t[l].x.l+=t[d].val,t[l].x.r+=t[d].val,t[r].x.l+=t[d].val,t[r].x.r+=t[d].val,t[d].val=0;
    25 }
    26 void build(int d,int l,int r)
    27 {
    28     if ((t[d].l=l)==(t[d].r=r)) { t[d].x.s[0]=0,t[d].x.l=t[d].x.r=s[l],t[d].x.s[1]=t[d].x.s[3]=t[d].x.s[2]=1; return; }
    29     int mid=l+r>>1;
    30     build(d*2,l,mid),build(d*2+1,mid+1,r),t[d].x=t[d*2].x+t[d*2+1].x;
    31 }
    32 data query(int d,int l,int r)
    33 {
    34     if (t[d].l==l&&t[d].r==r) return t[d].x;
    35     if (t[d].val) pushdown(d);
    36     int mid=t[d].l+t[d].r>>1;
    37     if (r<=mid) return query(d*2,l,r); else if (l>mid) return query(d*2+1,l,r); else return query(d*2,l,mid)+query(d*2+1,mid+1,r);
    38 }
    39 void modify(int d,int l,int r,int k)
    40 {
    41     if (t[d].l==l&&t[d].r==r) { t[d].val+=k,t[d].x.l+=k,t[d].x.r+=k; return; }
    42     if (t[d].val) pushdown(d);
    43     int mid=t[d].l+t[d].r>>1;
    44     if (r<=mid) modify(d*2,l,r,k); else if (l>mid) modify(d*2+1,l,r,k); else modify(d*2,l,mid,k),modify(d*2+1,mid+1,r,k); 
    45     t[d].x=t[d*2].x+t[d*2+1].x;
    46 }
    47 int main()
    48 {
    49     scanf("%d",&n);
    50     for (int i=1;i<=n;i++) scanf("%d",&s[i]),s[i-1]=s[i]-s[i-1];
    51     build(1,1,n-1),scanf("%d",&q);
    52     for (int l,r,a,b;q;q--)
    53     {
    54         scanf("%s",op),scanf("%d%d",&l,&r);
    55         if (op[0]=='B') l==r?puts("1"):printf("%d
    ",query(1,l,r-1).s[3]); 
    56         else
    57         {
    58             scanf("%d%d",&a,&b);
    59             if (l!=1) modify(1,l-1,l-1,a);
    60             if (l!=r) modify(1,l,r-1,b);
    61             if (r!=n) modify(1,r,r,-(a+(r-l)*b));    
    62         }
    63     }
    64 }
  • 相关阅读:
    我们需要什么,技术还是idea
    爱上一个人,忘记一个人
    我的大学
    早上8点,轻轨抛锚时... ...
    我的秋天
    通过注册表以及文件操作的方式获取当前正在实际使用的物理网卡MAC地址
    【分享】全局字符串转换为局部变量存储防止软件被静态分析暴露敏感字符串
    正确获取硬盘序列号源码
    【转】Xvid参数详解
    VerifyFile验证文件签名
  • 原文地址:https://www.cnblogs.com/Comfortable/p/11254193.html
Copyright © 2020-2023  润新知