題意:有點難懂; 初始序列a[n],值都爲0,有兩個操作,
1.區間【l,r】內數++,
2.執行操作編號在[l,r]內的所有操作各一次,保證r小於當前操作的編號。m次操作結束後,你要告訴馬爺A數組變成什麼樣子了。 意思就是說【l,r】區間(區間內的數此時爲操作的編號)內的數即以前的操作編號的,按這些操作編號再操作一次。
題解:建兩顆線段樹,一顆維護處究竟每個操作1的區間加了多少次1. 把M次操作倒着更新維護,因爲操作2有點遞歸的思想,正着無法在短時間內知道每個區間加多少1,
第二棵在維護所有區間執行操作1後的,查詢即可。
細節:就是第一課樹實際是單點修改+區間修改,但是騷操作了一下,只用寫一個區間修改。
//題外話:權值線段樹沒有區間修改
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1e5 + 5;
const int INF = 0x3f3f3f3f;
const ll mod = 1e9 + 7;
int op[maxn],l[maxn],r[maxn];
ll sum[maxn*4],lazy[maxn*4];
void push(int p){
sum[p]=(sum[p<<1]+sum[p<<1|1])%mod;
}
void pushdown(int l,int r,int p){
int mid=(l+r)/2;
if(lazy[p]){
lazy[p<<1]+=lazy[p]; lazy[p<<1]%=mod;
lazy[p<<1|1]+=lazy[p]; lazy[p<<1|1]%=mod;
sum[p<<1]+=lazy[p]*(mid-l+1); sum[p<<1]%=mod;
sum[p<<1|1]+=lazy[p]*(r-mid); sum[p<<1|1]%=mod;
lazy[p]=0;
}
}
void build(int l,int r,int p){
if(l==r){
sum[p]=0; lazy[p]=0;
return ;
}
int mid=(l+r)/2;
build(l,mid,p<<1);
build(mid+1,r,p<<1|1);
push(p);
}
void update(int l,int r,int L,int R,ll val,int p){
if(L<=l&&r<=R){
lazy[p]+=val; lazy[p]%=mod;
sum[p]+=val*(r-l+1); sum[p]%=mod;
return ;
}
pushdown(l,r,p);
int mid=(l+r)/2;
if(L<=mid) update(l,mid,L,R,val,p<<1);
if(R>mid) update(mid+1,r,L,R,val,p<<1|1);
push(p);
}
ll query(int l,int r,int L,int R,int p){
if(L<=l&&r<=R){
return sum[p]%mod;
}
pushdown(l,r,p);
int mid=(l+r)/2;
ll ans=0;
if(L<=mid) ans+=query(l,mid,L,R,p<<1);
if(R>mid) ans+=query(mid+1,r,L,R,p<<1|1);
return ans%mod;
}
ll tp[maxn];
int main(){
int n,m; cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>op[i]>>l[i]>>r[i];
}
build(1,m,1);
for(int i=m;i>=1;i--){
if(op[i]==1) update(1,m,i,i,1,1);
else{
ll Q=query(1,m,i,i,1);//從後往前確定操作1的次數
update(1,m,l[i],r[i],Q+1,1);
}
}
for(int i=1;i<=m;i++){//每個操作1究竟執行幾次
tp[i]=query(1,m,i,i,1);
}
memset(lazy,0,sizeof(lazy));
memset(sum,0,sizeof(sum));
build(1,n,1);
for(int i=1;i<=m;i++){
if(op[i]==1){
update(1,n,l[i],r[i],tp[i],1);
}
}
for(int i=1;i<=n;i++){
cout<<query(1,n,i,i,1)<<" ";
}
cout<<endl;
}