链接:https://ac.nowcoder.com/acm/contest/946/D
来源:牛客网
筱马爱线段树(差分、线段树
筱玛是一个热爱线段树的好筱玛。
筱玛的爷爷马爷在游戏中被筱玛吊打了,于是他恼羞成怒,决定给筱玛出这样一道数据结构题:
给定一个长度为n的数组A,刚开始每一项的值均为0。
支持以下两种操作,操作共m次:
1 l r:Al∼Ar的每一项的值加上1。
2 l r:执行操作编号在[l,r]内的所有操作各一次,保证r小于当前操作的编号。
m次操作结束后,你要告诉马爷A数组变成什么样子了。
由于答案可能会很大,你只需要输出数组
A中的每个数在模1e+7意义下的值。
示例1
输入
4 3
1 1 3
2 1 1
1 1 3
输出
3 3 3 0
备注:
对于100%的数据:1≤n≤1e5,1≤m≤1e5
1、差分思路:
1、差分题解:
#include<iostream>
using namespace std;
const int MAXN=1e5+100;
const int MOD=1e9+7;
typedef long long ll;
ll ans[MAXN],t[MAXN];
struct node
{
ll opt,l,r;
}p[MAXN];
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++)
{
cin>>p[i].opt>>p[i].l>>p[i].r;
}
t[m]=1;
for(int i=m;i>=1;i--)
{
t[i]=(t[i]+t[i+1]);
if(p[i].opt==2)
{
t[p[i].l-1]=(t[p[i].l-1]-t[i])%MOD;
t[p[i].r]=(t[p[i].r]+MOD+t[i])%MOD;
}
else if(p[i].opt==1)
{
ans[p[i].l]=(ans[p[i].l]+MOD+t[i])%MOD;
ans[p[i].r+1]=(ans[p[i].r+1]-t[i])%MOD;
}
}
for(int i=1;i<=n;i++)
{
ans[i]=(ans[i-1]+MOD+ans[i])%MOD;
cout<<ans[i]<<' ';
}
}
2、线段树思路:
2、线段树题解:
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
const int N=1e5+10;
const ll mod=1e9+7;
int n,m;
struct node
{
int ty,l,r;
}a[N];
ll s1[N*4],l1[N*4],s2[N*4],l2[N*4],len[N*4];
void push1(int id,int l,int r)
{
if(l1[id])
{
//printf("id:%d\n",id);
l1[id<<1]+=l1[id];
l1[id<<1|1]+=l1[id];
s1[id<<1]=(s1[id<<1]+len[id<<1]*l1[id])%mod;
s1[id<<1|1]=(s1[id<<1|1]+len[id<<1|1]*l1[id])%mod;
l1[id]=0;
}
}
void up1(int id,int l,int r,int ql,int qr,ll val){
if(ql<=l&&r<=qr){
l1[id]+=val;
ll len=r-l+1;
s1[id]=(s1[id]+len*val);
return ;
}
push1(id,l,r);
int mid=l+r>>1;
if(ql<=mid)up1(id<<1,l,mid,ql,qr,val);
if(qr>mid) up1(id<<1|1,mid+1,r,ql,qr,val);
s1[id]=s1[id<<1]+s1[id<<1|1];
}
void push2(int id,int l,int r)
{
if(l2[id])
{
l2[id<<1]+=l2[id];
l2[id<<1|1]+=l2[id];
s2[id<<1]=(s2[id<<1]+len[id<<1]*l2[id])%mod;
s2[id<<1|1]=(s2[id<<1|1]+len[id<<1|1]*l2[id])%mod;
l2[id]=0;
}
}
ll qu1(int id,int l,int r,int pos,int ty){
if(l==r) {
if(ty==1) return s1[id];
return s2[id];
}
push1(id,l,r);
push2(id,l,r);
int mid=l+r>>1;
if(pos<=mid) return qu1(id<<1,l,mid,pos,ty);
return qu1(id<<1|1,mid+1,r,pos,ty);
}
void up(int id,int l,int r,int ql,int qr,ll val){
if(ql<=l&&r<=qr){
l2[id]+=val;
ll len=r-l+1;
s2[id]=(s2[id]+len*val);
return ;
}
push2(id,l,r);
int mid=l+r>>1;
if(ql<=mid)up(id<<1,l,mid,ql,qr,val);
if(qr>mid) up(id<<1|1,mid+1,r,ql,qr,val);
s2[id]=s2[id<<1]+s2[id<<1|1];
}
void build(int id,int l,int r){
len[id]=r-l+1;
if(l==r) return ;
int mid=l+r>>1;
build(id<<1,l,mid);
build(id<<1|1,mid+1,r);
}
int main(){
cin>>n>>m;
for(int i=1;i<=m;++i){
scanf("%d%d%d",&a[i].ty,&a[i].l,&a[i].r);
}
build(1,1,n);
for(int i=m;i>=1;--i){
if(a[i].ty==2){
ll val=qu1(1,1,n,i,1);
up1(1,1,n,a[i].l,a[i].r,val+1);
}
else {
up1(1,1,n,i,i,1);
}
}
for(int i=1;i<=m;i++){
if(a[i].ty==1){
ll val=qu1(1,1,n,i,1);
up(1,1,n,a[i].l,a[i].r,val);
}
}
for(int i=1;i<=n;i++){
printf("%lld ",qu1(1,1,n,i,2)%mod);
}
puts("");
}
3、树状数组题解(会超时):
#include<iostream>
#include<string.h>
using namespace std;
const int MAXN=1e5+100;
const int MOD=1e9+7;
typedef long long ll;
ll C[MAXN],A[MAXN];
ll map[MAXN];
int lowbit(int t)
{
return t&(-t);
}
int secondlowbit(int t)
{
int bit=1;
while(bit<t)
{
bit<<=1;
}
return bit>>=1;
}
void build(int n)
{
int j=1;
while(j<=n)
{
for(int i=j-1;i>=j-lowbit(j)+1;i-=lowbit(i)) //j为奇数 j-lowbit(j)+1=j;
// i>=secondlowbit(j)&& // j为2^n j-lowbit(j)+1=1;
// for(int i=j-1;i>=1;i-=lowbit(i)) //j为非2^n偶数 j-lowbit(j)+1;
C[j]=(C[j]+C[i]);
j++;
}
return;
}
ll sum(int R)
{
ll sum=0,ss=0;
for(int i=R;i>=1;i-=lowbit(i))
sum+=C[i];
// for(int i=L-1;i>=1;i-=lowbit(i))
// ss+=C[i];
return (sum-ss)%MOD;
}
int main()
{
int n,m;
cin>>n>>m;
memset(C,0,(n+1)*sizeof(C[0]));
int j=0;
for(int i=1;i<=m;i++)
{
int opt=0,l=0,r=0;
cin>>opt>>l>>r;
if(opt==1)
{
if(C[l]==0)
{
map[++j]=l;
}
if(C[r+1]==0)
{
map[++j]=r+1;
}
C[l]+=1;
C[r+1]-=1;
}
else if(opt==2)
{
for(int h=1;h<=j;h++)
C[map[h]]=C[map[h]]*2;
}
}
build(n);
for(int i=1;i<=n;i++)
{
cout<<sum(i)<<' ';
}
}