分苹果--(区间操作,线段树与树状数组)

小朋友排成一排,老师给他们分苹果。
小朋友从左到右标号1…N。有M个老师,每次第i个老师会给第Li个到第Ri个,一共Ri-Li+1个小朋友每人发Ci个苹果。
最后老师想知道每个小朋友有多少苹果。

数据规模和约定
100%的数据,N、M≤100 000,1≤Li≤Ri≤N,0≤Ci≤100。

输入
第一行两个整数N、M,表示小朋友个数和老师个数。
接下来M行,每行三个整数Li、Ri、Ci,意义如题目表述。
输出
一行N个数,第i个数表示第i个小朋友手上的水果。
样例输入
5 3
1 2 1
2 3 2
2 5 3
样例输出
1 6 5 3 3

线段树做法:

//这里分苹果是区间修改,且数据量比较大,因此使用线段树来解决
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 100002;
int sum[maxn<<2],Lazy[maxn<<2]; //线段树一般要开辟4倍于数据量的存储空间,区间求和需要懒惰标记lazy 
int n,m;

void Pushup(int k) //上推函数更新结点 
{
  sum[k] = sum[k*2]+sum[k*2+1];
}

void Pushdown(int rt,int ln,int rn) //下推函数
{
	if(Lazy[rt])
	{
		Lazy[rt*2]+=Lazy[rt];
		Lazy[rt*2+1]+=Lazy[rt];
		
		sum[rt*2]+=Lazy[rt]*ln;
		sum[rt*2+1]+=Lazy[rt]*rn;
		Lazy[rt] = 0;
	}
} 

void Updata(int L,int R,int C,int left,int right,int rt)//区间修改
{
	if(L<=left&&right<=R)
	{
		sum[rt]+=C*(right-left+1);
		Lazy[rt]+=C;
		return ;
	}
	
	int m = (left+right)>>1;
	Pushdown(rt,m-left+1,right-m); //下推
	 
	if(L<=m) Updata(L,R,C,left,m,rt<<1);
	if(R>m) Updata(L,R,C,m+1,right,(rt<<1)+1);
	Pushup(rt); //上推更新节点 
 } 
 
 //区间查询
int Query(int L,int R,int l,int r,int rt)
{
	if(L<=l&&r<=R)
	{
		return sum[rt];
	}
	
	int m = (l+r)>>1;
	Pushdown(rt,m-l+1,r-m);
	
	int ans = 0;
	if(L<=m) ans+=Query(L,R,l,m,rt<<1);
	if(R>m) ans+=Query(L,R,m+1,r,(rt<<1)+1);
	
	return ans;
 } 
 
int main()
{
	cin>>n>>m;
	int l,r,c;
	memset(sum,0,sizeof(sum));
	memset(Lazy,0,sizeof(Lazy));
	for(int i =1;i<=m;i++)
	{
		cin>>l>>r>>c;
		Updata(l,r,c,1,n,1);
	}
	for(int i = 1;i<=n;i++)
	{
		printf("%d ",Query(i,i,1,n,1));
	}
	cout<<endl;
	return 0;
}

树状数组做法:

#include "iostream"
#include "cstring"
#include "algorithm"
using namespace std;
//typedef long long ll;
//const int INF = 1e9;
const int maxn = 100010;
int A[maxn];
int n, m;
int lowbit(int x) {
    return x & -x;
}
void update(int x, int k) {
    while(x <= n) {
        A[x] += k;
        x += lowbit(x);
    }
}
int query(int x) {
    int res = 0;
    while(x) {
        res += A[x];
        x -= lowbit(x);
    }
    return res;
}
int main() {
    cin >> n >> m;
    for(int i = 0; i < m; ++i) {
        int l, r, k;
        cin >> l >> r >> k;
        update(l, k);    //这里为核心代,本质上是区间修改
        update(r + 1, -k);
    }
    for(int i = 1; i <= n; ++i) cout << query(i) << " ";
    cout << endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值