CodeChef.July.5th - Addition and Multiplication

Addition and Multiplication

https://www.codechef.com/problems/ADDMUL
You are given a one dimensional integer array A of length N. You need to maintain the array under Q queries of the following four types. Assume 1-based indexing and M = 109 + 7.

Query 1 : 1 x y v
This implies adding v to array A to all the indices from x to y, i.e.,
for (i = x; i <= y; i++)
Ai += v;
Ai %= M;

Query 2 : 2 x y v
This implies multiplying the scalar v with the array A for all the indices from x to y, i.e.,
for (i = x; i <= y; i++)
Ai *= v
Ai %= M

Query 3 : 3 x y v
This implies initializing the array A at all the indices from x to y with the value v, i.e.,
for (i = x; i <= y; i++)
Ai = v

Query 4 : 4 x y
This is a report query which needs to find the sum of the values in A from x to y, i.e.,
sum = 0;
for (i = x; i <= y; i++)
sum += Ai
sum %= M
Output sum.

Note: a%b represents the remainder of a when divided by b.
Input

First line contains two space separated integers N, Q.
Next line contains N space separated integers denoting the array A.
Next Q lines contain queries which can be of any of the above four types.
Output

For each query of type 4, output a single integer corresponding to the answer in a single line.
Constraints

  • 1 ≤ N ≤ 105
  • 1 ≤ Q ≤ 105
  • 1 ≤ Initial value of Ai ≤ 109
  • 1 ≤ v ≤ 109

Subtasks

  • Subtask 1: Queries are of type 1, 3 and 4. Points - 5.
  • Subtask 2: Queries are of type 2, 3 and 4. Points - 5.
  • Subtask 3: Queries are of type 1, 2 and 4. Points - 30.
  • Subtask 4: All the queries are present. Points - 60.

Example

Input:
4 4
1 2 3 4
4 1 4
1 1 3 10
2 2 4 2
4 1 4

Output:
10
69

Explanation

Initial A : [1, 2, 3, 4]
Result of first query : 1 + 2 + 3 + 4 = 10
A after second query: [ 11, 12, 13, 4]
A after third query : [ 11, 24, 26, 8]
Result of fourth query : 11 + 24 + 26 + 8 = 69

题意:是一个很裸的线段树,题目没有什么隐藏的意思。

是一个只要学会之后就很水的线段树的多种区间更新的结合,在上个月(6月)一次邀请赛中还碰见了,只不过当时太水并不会,而这次在CC的月赛里碰到这个题之后,便决定高一下了…

总共三种更新操作:

  • (l, r) 区间内 + c
  • (l, r) 区间内 * c
  • (l, r) 区间内 全部置换为 c

还有一个就是区间查询,这个没什么的.

线段树维护三个值: sum(总和) , add(加标识), mul(乘标识)

我也是在通过大牛的处理方式才学习到的.
每次更新,乘操作要先于加操作

乘操作 : 对两个lazy标识 和 sum 乘上c进行更新

加操作 : 只对add 和 sum进行更新, add 直接加c, sum加上区间长度乘c

置换操作 : 就是进行一次乘0的操作, 然后加c就OK了

code:

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<string>
#include<stack>
#include<queue>
#include<vector>
#include<map>
#include<set>
#include<iostream>
#define pb push_back
#define INF 0x3f3f3f3f
using namespace std;
typedef unsigned long long ULL;
typedef long long LL;
const int mod = 1000000007;
const int N = 100005;
int data[N];
struct node{
    int sum;
    int add, mul;
    void init(){ add=0; mul=1; }
} tree[N<<2];
int n, q;
void update(int l, int r, int rt, int ul, int ur, int mul, int add);
void pushdown(int rt, int l, int r){
    int mid = (l+r)>>1;
    update(l, mid, rt<<1, l, mid, tree[rt].mul, tree[rt].add);
    update(mid+1, r, rt<<1|1, mid+1, r, tree[rt].mul, tree[rt].add);
    tree[rt].init();
}
int query(int l, int r, int rt, int ql, int qr){
    if(ql <= l && r <= qr){
        //printf("l - %d & r - %d -> %d\n", l, r, tree[rt].sum);
        return tree[rt].sum;
    }
    pushdown(rt, l, r);
    int mid = (l+r)>>1;
    LL ret = 0;
    if(ql <= mid) ret = (ret + (LL)query(l, mid, rt<<1, ql, qr))%mod;
    if(qr > mid) ret = (ret + (LL)query(mid+1, r, rt<<1|1, ql, qr))%mod;
    //tree[rt].sum = (tree[rt<<1].sum + tree[rt<<1|1].sum)%mod;
    return ret%mod;
}
void update(int l, int r, int rt, int ul, int ur, int mul, int add){
    if(ul <= l && r <= ur){
        if(mul != 1){
            tree[rt].sum = ((LL)tree[rt].sum * mul)%mod;
            tree[rt].add = ((LL)tree[rt].add * mul)%mod;
            tree[rt].mul = ((LL)tree[rt].mul * mul)%mod;
        }
        if(add){
            int len = r - l + 1;
            tree[rt].sum = ((LL)tree[rt].sum + (LL)len * add)%mod;
            tree[rt].add = ((LL)tree[rt].add + add)%mod;
        }
        //printf("  l - %d & r - %d -> sum : %lld\n", l, r, tree[rt].sum);
        return ;
    }
    pushdown(rt, l, r);
    int mid = (l+r)>>1;
    if(ul <= mid) update(l, mid, rt<<1, ul, ur, mul, add);
    if(ur > mid) update(mid+1, r, rt<<1|1, ul, ur, mul, add);
    tree[rt].sum = (tree[rt<<1].sum + tree[rt<<1|1].sum)%mod;
}
void build(int l, int r, int rt){
    tree[rt].init();
    tree[rt].sum = 0;
    if(l == r){
        tree[rt].sum = data[l];
        return ;
    }
    int mid = (l+r)>>1;
    build(l, mid, rt<<1);
    build(mid+1, r, rt<<1|1);
    tree[rt].sum = (tree[rt<<1].sum + tree[rt<<1|1].sum)%mod;
}
void solve(){
    scanf("%d %d", &n, &q);
    for(int i=1; i<=n; i++) scanf("%d", &data[i]);
    build(1, n, 1);
    for(int i=0; i<q; i++){
        int op, a, b, c;
        scanf("%d %d %d", &op, &a, &b);
        if(op<4){
            scanf("%d", &c);
            if(op == 1) update(1, n, 1, a, b, 1, c); // +
            else if(op == 2) update(1, n, 1, a, b, c, 0); // *
            else update(1, n, 1, a, b, 0, c); // trans
        } else {
            printf("%d\n", query(1, n, 1, a, b));
        }
        //for(int j=1; j<=n; j++) printf("%d : %lld\n", j, query(1, n, 1, j, j));
    }
}
int main(void){
#ifdef DK
    freopen("/home/dk/桌面/1.in","r",stdin);
#endif // DK
    solve();
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值