UESTC 1597 An easy problem C 线段树+延迟操作+一次函数

129 篇文章 0 订阅
117 篇文章 2 订阅

An easy problem C

Time Limit: 4000/2000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others)


Submit  Status
N个数排成一列,有三种操作。1.给一段区间内的每个数乘上一个非负整数。2.给一段区间内的每个数加上一个非负整数.3.询问一段区间的和模上P的值。


Input

第一行两个整数N(1≤N≤100000)表示数的个数,P(1≤P≤1000000000)表示模的值。接下来一行N个整数ai(0≤ai≤1000000000),接下来一行一个整数M(1≤M≤100000)表示操作数量,接下来M行每行描述一个操作。第一种操作描述:1 L R C(0≤C≤1000000000),表示把L到R这段区间每个数乘上一个C。第二种操作描述:2 L R C(0≤C≤1000000000),表示把L到R这段区间每个数加上一个C。第三种操作3 L R 表示询问L到R这段区间内的数的和模上P的值。


Output

对面每个询问,输出对应的答案,每个询问占一行。


Sample input and output

Sample Input Sample Output
7 43
1 2 3 4 5 6 7
5
1 2 5 5
3 2 4
2 3 7 9
3 1 3
3 4 7
2
35
8


Source

2017 UESTC Training for Data Structures

UESTC 1597 An easy problem C


My Solution

题意:N个数排成一列,有三种操作。1.给一段区间内的每个数乘上一个非负整数。
2.给一段区间内的每个数加上一个非负整数.3.询问一段区间的和模上P的值。


线段树+延迟操作+一次函数
用2个lazy数组,分别为lazya[i], lazyb[i],
表示 lazya[i] * x + lazyb[i],
即用一个一次函数,或者说一次系数和常数项 来表示每个节点lazy数组的情况。
每次pushdown的时候,如果lazya或者lazyb有至少其中一个值需要向下传递,
则都一起操作。
先把 lazya的值传递给子节点的lazya和lazyb,然后把lazyb的值传递给子节点的lazyb。
且把lazyb传递给子节点的sum的时候,要 sum[son] = mod(sum[son] + (区间长度)*lazyb)。
然后pushup的时候维护sum%p即可。
2个注意点,一、每次+ or * 都要先取模,二、要用long long
复杂度 O(nlogn)


#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
const LL MAXN = 1e5 + 8;

LL sum[4*MAXN], lazya[4*MAXN], lazyb[4*MAXN];
LL findans, MOD;
LL sz;
inline LL mod(LL x)
{
    return x - x / MOD * MOD;
}
inline void init()
{
    memset(sum, 0, sizeof sum);
    memset(lazyb, 0, sizeof lazyb);
    for(LL i = 0; i < 4*MAXN; i++) lazya[i] = 1;
}
inline void pushdown(LL l, LL r, LL Ind)
{
    LL mid = (l + r) >> 1;
    sum[Ind<<1] = mod(sum[Ind<<1] * lazya[Ind]);
    sum[Ind<<1] = mod(sum[Ind<<1] + mod((mid - l + 1)*lazyb[Ind]));
    sum[(Ind<<1) + 1] = mod(sum[(Ind<<1) + 1] * lazya[Ind]);
    sum[(Ind<<1) + 1] = mod(sum[(Ind<<1) + 1] + mod((r - (mid+1) + 1)*lazyb[Ind]));
    lazya[Ind<<1] = mod(lazya[Ind<<1]*lazya[Ind]);
    lazya[(Ind<<1) + 1] = mod(lazya[(Ind<<1) + 1]*lazya[Ind]);
    lazyb[Ind<<1] = mod(lazyb[Ind<<1]*lazya[Ind]);
    lazyb[(Ind<<1) + 1] = mod(lazyb[(Ind<<1) + 1]*lazya[Ind]);
    lazya[Ind] = 1;
    lazyb[Ind<<1] = mod(lazyb[Ind<<1] + lazyb[Ind]); lazyb[(Ind<<1) + 1] = mod(lazyb[(Ind<<1) + 1] + lazyb[Ind]);
    lazyb[Ind] = 0;
}
inline void pushup(LL Ind)
{
    sum[Ind] = mod(sum[Ind<<1] + sum[(Ind<<1) + 1]);
}
inline void _Query(LL a, LL b, LL l, LL r, LL Ind){
    if(a <= l && r <= b){findans = mod(findans + sum[Ind]); return; }
    LL mid = (l + r) >> 1;
    if(lazya[Ind] != 1 || lazyb[Ind] != 0) pushdown(l, r, Ind);
    if(a <= mid) { _Query(a, b, l, mid, Ind<<1); }
    if(b > mid) { _Query(a, b, mid + 1, r, (Ind<<1) + 1); }
    pushup(Ind);
}

inline void _Modify(LL a, LL b, LL l, LL r, LL Ind, LL d, bool f){
    if(a <= l && r <= b){
        if(f){
            sum[Ind] = mod(sum[Ind] * d);
            lazya[Ind] = mod(lazya[Ind] * d);
            lazyb[Ind] = mod(lazyb[Ind] * d);
        }
        else{
            sum[Ind] = mod(sum[Ind] + mod((r - l + 1)*d)); //!
            lazyb[Ind] = mod(lazyb[Ind] + d);
        }
        return;
    }
    LL mid = (l + r) >> 1;
    if(lazya[Ind] != 1 || lazyb[Ind] != 0) pushdown(l, r, Ind);
    if(a <= mid){ _Modify(a, b, l, mid, Ind<<1, d, f); }
    if(b > mid){ _Modify(a, b, mid + 1, r, (Ind<<1) + 1, d, f); }
    pushup(Ind);
}

inline void Query(LL a, LL b) {return _Query(a, b, 1, sz, 1);}
inline void Modify(LL a,LL b,LL d, bool f){return _Modify(a, b, 1, sz, 1, d, f);}

int main()
{
    #ifdef LOCAL
    freopen("c.txt", "r", stdin);
    //freopen("c.out", "w", stdout);
    LL T = 1;
    while(T--){
    #endif // LOCAL
    //ios::sync_with_stdio(false); cin.tie(0);

    LL n, q, t, l, r, c, i;
    scanf("%lld%lld", &n, &MOD);
    sz = n;
    init();
    for(i = 1; i <= n; i++){
        scanf("%lld", &c);
        Modify(i, i, c, false);
    }

    scanf("%lld", &q);
    while(q--){
        scanf("%lld", &t);
        if(t == 1){
            scanf("%lld%lld%lld", &l, &r, &c);
            Modify(l, r, c, true);
        }
        else if(t == 2){
            scanf("%lld%lld%lld", &l, &r, &c);
            Modify(l, r, c, false);
        }
        else{
            scanf("%lld%lld", &l, &r);
            findans = 0;
            Query(l, r);
            printf("%lld\n", findans);
        }
    }

    #ifdef LOCAL
    cout << endl;
    }
    #endif // LOCAL
    return 0;
}


  Thank you!

                                                                                                                                             ------from ProLights

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值