[差分][线段树] 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 \times (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\n",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 }

 

posted @ 2019-07-27 10:51  BEYang_Z  阅读(305)  评论(0编辑  收藏  举报