筱马爱线段树(差分、线段树)

链接: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)<<' ';
    	
	}

           
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值