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

Posted li_wen_zhuo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
}

以上是关于The 13th Chinese Northeast Contest H. Skyscraper(差分+树状数组)的主要内容,如果未能解决你的问题,请参考以下文章

The 13th Chinese Northeast Contest C. Line-line Intersection(平面几何)

The 13th Chinese Northeast Collegiate Programming Contest E题

The 15th Chinese Northeast Collegiate H - Loneliness(思维,构造)

The 15th Chinese Northeast Collegiate H - Loneliness(思维,构造)

The 15th Chinese Northeast Collegiate C. Vertex Deletion(树形dp)

The 15th Chinese Northeast L. k-th Smallest Common Substring(广义SAM,对节点字典序排序)