Color the ball

本文介绍了一种区间涂色问题的高效解决方案,通过树状数组、简单数组操作及线段树实现快速区间更新与查询,适用于算法竞赛及实际场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


Problem Description
N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的“小飞鸽"牌电动车从气球a开始到气球b依次给每个气球涂一次颜色。但是N次以后lele已经忘记了第I个气球已经涂过几次颜色了,你能帮他算出每个气球被涂过几次颜色吗?
 

Input
每个测试实例第一行为一个整数N,(N <= 100000).接下来的N行,每行包括2个整数a b(1 <= a <= b <= N)。
当N = 0,输入结束。
 

Output
每个测试实例输出一行,包括N个整数,第I个数代表第I个气球总共被涂色的次数。
 

Sample Input
3 1 1 2 2 3 3 3 1 1 1 2 1 3 0
 

Sample Output
1 1 1 3 2 1


题解:如果区间[a,b]都加上1,那么我将a这点加上1,求[a,b]区间任意一个时,我对前面数组求和不就得到了结果吗?不用每次都加。树状数组就能解决求区间和问题。


树状数组:

#include <iostream>
#include <cstring>
#include <cstdio>
#define mem(a) memset(a,0,sizeof(a));

using namespace std;

int a[100005];

void update(int x,int n,int plus) //更新数组 
{
	while(x <= n)
	{
		a[x] += plus;
		x +=  x & (-x);
	}
}

int getSum(int n)
{
	int res = 0;
	while(n > 0)
	{
		res += a[n];
		n -= n & (-n);
	}
	
	return res;
}

int main()
{
	int n;
	while(scanf("%d",&n) && n != 0)
	{
		mem(a);
		for(int i = 0;i < n;i++)
		{
			int l,r;
			scanf("%d%d",&l,&r);
			update(l,n,1);    //将l这个点加1 
			update(r + 1,n,-1); //求和时,r后面的需要减1,因为这些点不在要求修改的区间 
		}
		
		for(int i = 1;i < n;i++)
		{
			printf("%d ",getSum(i));
		}
		printf("%d\n",getSum(n));
	}
	
	
	return 0;
}

平常做法:

#include <iostream>
#include <cstring>
#include <cstdio>
#define mem(a) memset(a,0,sizeof(a));

using namespace std;

int a[100005];

int main()
{
	int n;
	while(scanf("%d",&n) && n != 0)
	{
		mem(a);
		for(int i = 0;i < n;i++)
		{
			int l,r;
			scanf("%d%d",&l,&r);
			a[l] += 1;          //l这里加1 
			a[r + 1] -= 1;      //r+1这里减1,以后再求前i项的和就得到了单点值 
		}
		
		int res = 0;
		for(int i = 1;i < n;i++)
		{
			a[i] += a[i - 1];
			printf("%d ",a[i]);
		}
		printf("%d\n",a[n] + a[n - 1]);
	}
	
	
	return 0;
}


线段树区间修改:其实就是减少递归次数。因为我最后(包括查询)肯定会访问到每一个节点。所以我可以这个时候更新孩子。


#include <iostream>
#include <cstdio>
#include <cstring>
#define mem(a) memset(a,0,sizeof(a));

using namespace std;

struct Node
{
	int l;
	int r;
	int sum;
};

Node a[500005];
int add[500005];

void segTree(int k,int l,int r)  //线段树的建立 
{
	a[k].l = l;             //区间信息 
	a[k].r = r;
	a[k].sum = 0;
	if(l == r)
	{
		return;
	}
	int mid = (l + r) >> 1;
	segTree(k << 1,l,mid);
	segTree((k << 1) | 1,mid + 1,r);
}

void pushDown(int k,int m)  //向下更新 
{
	if(add[k] != 0)        //该区间有更新的需要 
	{
		a[k << 1].sum += add[k] * (m - (m >> 1)); //左孩子更新 
		a[(k << 1) | 1].sum += add[k] * (m >> 1);
		add[k << 1] += add[k];                 //左孩子标记更新 
		add[(k << 1) | 1] += add[k];
		add[k] = 0;           //该区间已经向下更新了 
	}
}

void pushUp(int k)          //向上更新 
{
	a[k].sum = a[k << 1].sum + a[(k << 1) | 1].sum;
}

void update(int k,int l,int r,int plus)
{
	if(a[k].l == l && a[k].r == r)  //该区间找到,结束,等下次找到左右孩子才更新 
	{
		add[k] += plus;
		a[k].sum += (r - l + 1) * plus;
		return;
	}
	pushDown(k,a[k].r - a[k].l + 1);  //将该点孩子更新,因为要访问孩子了 
	int mid = (a[k].l + a[k].r) >> 1;
	if(l > mid)
	{
		update((k << 1) | 1,l,r,plus);
	}
	else if(r <= mid)
	{
		update(k << 1,l,r,plus);
	}
	else
	{
		update(k << 1,l,mid,plus);
		update((k << 1) | 1,mid + 1,r,plus);
	}
	pushUp(k);             //向上更新 
}

void query(int k,int n)
{
	pushDown(k,a[k].r - a[k].l + 1);
	if(a[k].l == a[k].r)
	{
		if(a[k].l == n)
		{
			printf("%d\n",a[k].sum);
		}
		else
		{
			printf("%d ",a[k].sum);
		}
		return;
	}
	query(k << 1,n);
	query((k << 1) | 1,n);
}

int main()
{
	int n;
	while(scanf("%d",&n) && n != 0)
	{
		mem(a);
		mem(add);
		segTree(1,1,n);
		int l,r;
		for(int i = 0;i < n;i++)
		{
			scanf("%d%d",&l,&r);
			update(1,l,r,1);
		}
		
		query(1,n);
	}
	
	
	return 0;
} 


内容概要:文章基于4A架构(业务架构、应用架构、数据架构、技术架构),对SAP的成本中心和利润中心进行了详细对比分析。业务架构上,成本中心是成本控制的责任单元,负责成本归集与控制,而利润中心是利润创造的独立实体,负责收入、成本和利润的核算。应用架构方面,两者都依托于SAP的CO模块,但功能有所区分,如成本中心侧重于成本要素归集和预算管理,利润中心则关注内部交易核算和获利能力分析。数据架构中,成本中心与利润中心存在多对一的关系,交易数据通过成本归集、分摊和利润计算流程联动。技术架构依赖SAP S/4HANA的内存计算和ABAP技术,支持实时核算与跨系统集成。总结来看,成本中心和利润中心在4A架构下相互关联,共同为企业提供精细化管理和决策支持。 适合人群:从事企业财务管理、成本控制或利润核算的专业人员,以及对SAP系统有一定了解的企业信息化管理人员。 使用场景及目标:①帮助企业理解成本中心和利润中心在4A架构下的运作机制;②指导企业在实施SAP系统时合理配置成本中心和利润中心,优化业务流程;③提升企业对成本和利润的精细化管理水平,支持业务决策。 其他说明:文章不仅阐述了理论概念,还提供了具体的应用场景和技术实现方式,有助于读者全面理解并应用于实际工作中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值