【线段树】295A Greg and Array

本文介绍了一种使用两个线段树的数据结构来解决序列更新与查询的问题。具体包括了如何通过线段树记录操作次数及操作值,并在一系列操作后快速获取更新后的序列值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Link:http://codeforces.com/contest/296/problem/C

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

/*
题意:给你初始序列,m个操作,再给k个询问,每个询问的范围l,r,
表示操作l到r都执行一遍,问最后的序列是怎么样的。
题解:两个线段树维护,第一个先求出每个操作的操作次数,第二个知道每个的操作
次数,得每个操作总共加上的值,求序列的值
*/

const int Maxn = 1e5+6;
const LL mod = 1e9+7;
struct Node{
    int l,r;
    LL lazy,sum;
    void update(LL x){
        sum += (LL)(r-l+1)*x;
        lazy += x;
    }
}node[Maxn*4];
int a[Maxn];
void push_up(int x){
    node[x].sum = node[x<<1].sum+node[x<<1|1].sum;
}
void push_down(int x){
    LL lazyval = node[x].lazy;
    if(lazyval){
        node[x<<1].update(lazyval);
        node[x<<1|1].update(lazyval);
        node[x].lazy = 0;
    }
}
void build(int x,int l,int r){
    node[x].l = l; node[x].r = r;
    node[x].lazy = node[x].sum = 0;
    if(l == r){
        node[x].sum = a[l];
    }
    else{
        int mid = (l+r)>>1;
        build(x<<1,l,mid);
        build(x<<1|1,mid+1,r);
        push_up(x);
    }
}

void update(int x,int l,int r,LL v){
    int L = node[x].l, R = node[x].r;
    if(L >= l && r >= R){
        node[x].update(v);
    }
    else{
        push_down(x);
        int mid = (L+R)>>1;
        if(mid >= l)
            update(x<<1,l,r,v);
        if(r > mid)
            update(x<<1|1,l,r,v);
        push_up(x);
    }
}

LL query(int x,int l,int r){
    int L = node[x].l, R = node[x].r;
    if(L >= l && r >= R){
        return node[x].sum;
    }
    else{
        push_down(x);
        LL res = 0;
        int mid = (L+R)>>1;
        if(mid >= l)
            res += query(x<<1,l,r);
        if(r > mid)
            res += query(x<<1|1,l,r);
        push_up(x);
        return res;
    }
}
struct Op{
    int l,r;
    LL d;
}op[Maxn];
int main(){
    int n,m,k;
    scanf("%d%d%d",&n,&m,&k);
    memset(a,0,sizeof(a));
    build(1,1,m);
    for(int i = 1; i <= n; i++)
        scanf("%d",&a[i]);
    for(int i = 1; i <= m; i++)
        scanf("%d%d%I64d",&op[i].l,&op[i].r,&op[i].d);
    while(k--){
        int l,r;
        scanf("%d%d",&l,&r);
        update(1,l,r,1LL);
    }
    for(int i = 1; i <= m; i++){
        LL x = query(1,i,i);
        op[i].d = op[i].d*x;
    }
    build(1,1,n);
    for(int i = 1; i <= m; i++){
        update(1,op[i].l,op[i].r,op[i].d);
    }
    for(int i = 1; i <= n; i++){
        LL x = query(1,i,i);
        if(i == n)
            printf("%I64d\n",x);
        else
            printf("%I64d ",x);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值