The 13th Chinese Northeast Contest H. Skyscraper(差分+树状数组)

题目描述

At the main street of Byteland, there will be built n skyscrapers, standing sequentially one next to other. If look leftside right, sequence of their height will be a1,a2,…,an.
Initially the street is empty, every skyscraper’s height is 0. Hamster is the leader of the construction team. In each stage, Hamster can select a range [l,r], then the team will work on this range. Specifically, assume the height sequence is h1,h2,…,hn, then hl,hl+1,…,hr will increase by 1 during this stage. When hi=ai holds for all i∈[1,n], the project will be closed.
The plan may be changed for many times. There will be m events of 2 kinds below:
1 l r k (1≤l≤r≤n,1≤k≤105), for all x∈[l,r], change ax to ax+k.
2 l r (1≤l≤r≤n), assume a1,a2,…,al−1,ar+1,ar+2,…,an=0, ask for the minimum number of required stages to close the project.

Input

The first line of the input contains an integer T(1≤T≤1000), denoting the number of test cases.
In each test case, there are two integers n,m(1≤n,m≤100000) in the first line, denoting the number of skyscrapers and events.
In the second line, there are n integers a1,a2,…,an(1≤ai≤100000).
For the next m lines, each line describes an event.
It is guaranteed that ∑n≤106 and ∑m≤106.

Output

For each query event, print a single line containing an integer, denoting the answer.

Example

input
1
5 4
1 3 1 4 5
2 1 5
1 3 4 2
2 2 4
2 1 5
output
7
6
6

题目描述

有n栋楼,第i栋楼的高度为a[i]。有m个操作:
给 [l,r] 区间内的楼高度+k。
查询[l,r]区间内的楼建好最少需要几个工期。(每个工期可以选择一个区间的楼,给每个楼都修建1层)。

题目分析

我们可以维护一个差分序列d[],对于一次查询 l < = i < = r l<=i<=r l<=i<=r

  1. 如果d[i]>0,则需要比前一栋楼多花d[i]的工期来修好这栋楼。
  2. 如果d[i]<=0,则在修建第 i-1 栋楼时可以顺带修好第i栋楼。

此外,维护差分序列还可以完美的处理好区间加数的问题(操作1)。

c[i]=(d[i]>0)?d[i]:0,那么区间[l,r]需要的工期为: a [ l ] + c [ l + 1 ] + c [ l + 2 ] + … … + c [ r − 1 ] + c [ r ] . a[l]+c[l+1]+c[l+2]+……+c[r-1]+c[r]. a[l]+c[l+1]+c[l+2]++c[r1]+c[r].

因为需要处理a[]的区间加数和单点查询,以及c[]的区间和查询和单点修改。因此我们可以用两个树状数组分别来维护a[]的差分数组和c[]。

代码如下
#include <iostream>
#include <cmath>
#include <cstdio>
#include <set>
#include <string>
#include <cstring>
#include <map>
#include <algorithm>
#include <stack>
#include <queue>
#include <bitset>
#define LL long long
#define ULL unsigned long long
#define PII pair<LL,LL>
#define PDD pair<double,double>
#define x first
#define y second
using namespace std;
const int N=1e5+5,INF=1e9+7;
int n,a[N],d[N];
LL tr1[N],tr2[N];		//tr1[]维护a[]的差分数组,tr2[]维护c[]
int lowbit(int x)		//树状数组模板函数
{
	return x&-x;
}
void add(LL tr[],int x,int c)
{
	for(int i=x;i<=n;i+=lowbit(i))
		tr[i]+=c;
}
LL sum(LL tr[],int x)
{
	LL res=0;
	for(int i=x;i;i-=lowbit(i))
		res+=tr[i];
	return res;
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		memset(tr1,0,sizeof tr1);
		memset(tr2,0,sizeof tr2);
		int m;
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			d[i]=a[i]-a[i-1];
			add(tr1,i,d[i]);
			if(d[i]>0) add(tr2,i,d[i]);
		}
		while(m--)
		{
			int op,l,r,k;
			scanf("%d%d%d",&op,&l,&r);
			if(op==1)
			{
				scanf("%d",&k);
				add(tr1,l,k),add(tr1,r+1,-k);		//l位置+k,r+1位置-k
				if(d[l]>0) add(tr2,l,-d[l]);		//修改tr2,如果原位置d[]<=0,则无需还原
				d[l]+=k;
				if(d[l]>0) add(tr2,l,d[l]);			//如果修改后位置<=0,则无需修改
				if(d[r+1]>0) add(tr2,r+1,-d[r+1]);
				d[r+1]-=k;
				if(d[r+1]>0) add(tr2,r+1,d[r+1]);
			}
			else printf("%lld\n",sum(tr1,l)+sum(tr2,r)-sum(tr2,l));		//即a[l]+sum(c[l+1一r])
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lwz_159

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值