牛客网__筱玛爱线段树

链接:https://ac.nowcoder.com/acm/contest/946/D
来源:牛客网
 

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述

筱玛是一个热爱线段树的好筱玛。

筱玛的爷爷马爷在游戏中被筱玛吊打了,于是他恼羞成怒,决定给筱玛出这样一道数据结构题:

给定一个长度为nn的数组AA,刚开始每一项的值均为00。

支持以下两种操作,操作共mm次:

1 l r1 l r:将Al∼ArAl∼Ar的每一项的值加上11。

2 l r2 l r:执行操作编号在[l,r][l,r]内的所有操作各一次,保证rr小于当前操作的编号。

mm次操作结束后,你要告诉马爷AA数组变成什么样子了。

由于答案可能会很大,你只需要输出数组AA中的每个数在模109+7109+7意义下的值。

输入描述:

第一行两个数n,mn,m,分别表示数组长度及操作次数。
接下来mm行,每行三个数opt,l,ropt,l,r,表示一次操作。

输出描述:

输出一行共nn个数,表示mm次操作结束后,A1∼AnA1∼An的值。

示例1

输入

复制

4 3
1 1 3
2 1 1
1 1 3

输出

复制

3 3 3 0

备注:

 

对于100%的数据,1≤n≤105,1≤m≤1051≤n≤105,1≤m≤105。

由于是对区间进行操作的所以要用线段树,但由于2操作的也是区间操作,所以就想到想把操作1的次数给算出来,故从后往前把2操作更新到1操作的区间上,然后再用一个线段树代表值,把前一棵线段树的每个1操作更新到区间上

两个线段树都要取mod(我以为分2操作的时候不用,错了好多发还是没查出来,最后才找出来)

(也可以用树状数组和差分和前缀和的思想去写,方便很多)

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

const int maxn = 1e6+9;
const ll mod = 1e9+7;
const int INF = 0x3f3f3f3f;

struct rt{
    int f;
    int x,y;
}a[maxn];

ll dat[maxn];
ll lazy[maxn];

void pushdown(int k){
    dat[k<<1]=(dat[k<<1]+lazy[k])%mod;
    dat[k<<1|1]=(dat[k<<1|1]+lazy[k])%mod;
    lazy[k<<1]=(lazy[k<<1]+lazy[k])%mod;
    lazy[k<<1|1]=(lazy[k<<1|1]+lazy[k])%mod;
    lazy[k]=0;
}

void add(int a,int b,int l,int r,int k,ll x){
    if(a<=l&&r<=b){
        dat[k]=(dat[k]+x)%mod;
        lazy[k]=(lazy[k]+x)%mod;
        return;
    }
    if(lazy[k])pushdown(k);
    int mid=(l+r)>>1;
    if(a<=mid)add(a,b,l,mid,k<<1,x);
    if(b>mid)add(a,b,mid+1,r,k<<1|1,x);
}

ll query(int L,int l,int r,int k){
    if(l==r){
        return dat[k];
    }
    if(lazy[k])pushdown(k);
    int mid=(l+r)>>1;
    if(L<=mid)return query(L,l,mid,k<<1);
    else return query(L,mid+1,r,k<<1|1);
}

struct rt_1{
    ll x,lazy;
}Dat[maxn];

void D_pushdown(int k){
    Dat[k<<1].x=(Dat[k<<1].x+Dat[k].lazy)%mod;
    Dat[k<<1|1].x=(Dat[k<<1|1].x+Dat[k].lazy)%mod;
    Dat[k<<1].lazy=(Dat[k<<1].lazy+Dat[k].lazy)%mod;
    Dat[k<<1|1].lazy=(Dat[k<<1|1].lazy+Dat[k].lazy)%mod;
    Dat[k].lazy=0;
}

void D_add(int a,int b,int l,int r,int k,ll x){
    if(a<=l&&r<=b){
        Dat[k].x=(Dat[k].x+x)%mod;
        Dat[k].lazy=(Dat[k].lazy+x)%mod;
        return;
    }
    if(Dat[k].lazy)D_pushdown(k);
    int mid=(l+r)>>1;
    if(a<=mid)D_add(a,b,l,mid,k<<1,x);
    if(b>mid)D_add(a,b,mid+1,r,k<<1|1,x);
}

ll D_query(int L,int l,int r,int k){
    if(l==r){
//            cout<<l<<" "<<Dat[k].x<<endl;
        return Dat[k].x;
    }
    if(Dat[k].lazy)D_pushdown(k);
    int mid=(l+r)>>1;
    if(L<=mid)return D_query(L,l,mid,k<<1);
    else return D_query(L,mid+1,r,k<<1|1);
}

int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    ll x;
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&a[i].f,&a[i].x,&a[i].y);
    }
    for(int i=m;i>=1;i--){
        if(a[i].f==1){
            add(i,i,1,m,1,1);
        }
        else{
            x=query(i,1,m,1);
            add(a[i].x,a[i].y,1,m,1,(x+1));
        }
    }
    for(int i=1;i<=m;i++){
        if(a[i].f==2)continue;
//        cout<<777<<endl;
        x=query(i,1,m,1);
//        cout<<888<<endl;
//        cout<<x<<" "<<a[i].x<<" "<<a[i].y<<endl;
        D_add(a[i].x,a[i].y,1,n,1,x);
//        cout<<333<<endl;
    }
//    cout<<555<<endl;
    for(int i=1;i<=n;i++){
        printf("%lld",D_query(i,1,n,1));
        if(i<n)printf(" ");
        else printf("\n");
    }
    return 0;
}
/*
1000 10
1 1 1
1 2 2
1 3 3
2 1 3
2 1 4
2 1 5
1 1 9
2 1 6
1 5 6
2 1 3
*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值