Luogu P1438 无聊的数列(线段树)

    xiaoxiao2024-12-19  11

    题目背景

    无聊的YYB总喜欢搞出一些正常人无法搞出的东西。有一天,无聊的YYB想出了一道无聊的题:无聊的数列。。。(K峰:这题不是傻X题吗)

    题目描述

    维护一个数列{a[i]},支持两种操作:

    1、1 L R K D:给出一个长度等于R-L+1的等差数列,首项为K,公差为D,并将它对应加到a[L]~a[R]的每一个数上。即:令a[L]=a[L]+K,a[L+1]=a[L+1]+K+D,

    a[L+2]=a[L+2]+K+2D……a[R]=a[R]+K+(R-L)D。

    2、2 P:询问序列的第P个数的值a[P]。

    输入输出格式

    输入格式:

     

    第一行两个整数数n,m,表示数列长度和操作个数。

    第二行n个整数,第i个数表示a[i](i=1,2,3…,n)。

    接下来的m行,表示m个操作,有两种形式:

    1 L R K D

    2 P 字母意义见描述(L≤R)。

     

    输出格式:

     

    对于每个询问,输出答案,每个答案占一行。

     

    输入输出样例

    输入样例#1: 复制

    5 2 1 2 3 4 5 1 2 4 1 2 2 3

    输出样例#1: 复制

    6

    说明

    数据规模:

    0≤n,m≤100000

    |a[i]|,|K|,|D|≤200

    Hint:

    有没有巧妙的做法?

    思路: 

    我们可以用前缀和来表示第 i 位实际的数是多少。

    当我们修改的时候, 

    [ l, r ] 首项 k, 公差 d,

    一、 l  位加上 k,

    二、(l , r ]  加上 d,

    三、r+1 加上 - (k + (r - l ) * d)

    我们最后求 第 p 位的数的时候, 就是求和 1~p 然后在加上原来的数。

     

    #include<bits/stdc++.h> #define ls (now << 1) #define rs (now << 1 | 1) using namespace std; const int N = 1e5+100; int a[N],n,m,l,r,k,d,p,op; long long val[N*4],tag[N*4]; void pushdown(int now, int l, int r){ if (!tag[now]) return; int mid = (l + r) >> 1; val[ls] += (mid - l) * tag[now]; val[rs] += (r - mid) * tag[now]; tag[ls] += tag[now]; tag[rs] += tag[now]; tag[now] = 0; } void build(int now, int l, int r){ if (l + 1 == r) return; int mid = (l + r) >> 1; build(ls,l,mid); build(rs,mid,r); } void Insert(int now, int l, int r, int a, int b, int w){ if (a <= l && b >= r - 1){ val[now] += (r - l) * w; tag[now] += w; return; } int mid = (l + r) >> 1; pushdown(now, l, r); if (a < mid) Insert(ls,l,mid,a,b,w); if (b >= mid) Insert(rs,mid,r,a,b,w); val[now] = val[ls] + val[rs]; } long long Query(int now, int l, int r, int a, int b){ long long ans = 0; if (a <= l && b >= r - 1){ return val[now]; } int mid = (l + r) >> 1; pushdown(now,l,r); if (a < mid) ans += Query(ls,l,mid, a,b); if (b >= mid) ans += Query(rs,mid,r,a,b); return ans; } int main(){ scanf("%d%d",&n,&m); for (int i = 1; i <= n; ++i) scanf("%d",&a[i]); build(1,1,n+1); for (int i = 0; i < m; ++i){ scanf("%d",&op); if (op == 1){ scanf("%d%d%d%d",&l,&r,&k,&d); Insert(1,1,n+1,l,l,k); if (l != r) Insert(1,1,n+1,l+1,r,d); if (r < n) Insert(1,1,n+1,r+1,r+1,-(k+(r-l)*d)); } else { scanf("%d",&p); long long ans = Query(1,1,n+1,1,p); printf("%lld\n",ans+a[p]); } } return 0; }

     

    最新回复(0)