GYM 102220 problem H Skyscraper 樹狀數組

將近一年前寫的題目了 又翻出來看看

題目鏈接:H Skyscraper

思路:用線段樹維護差分數組 

設b[i]=a[i]-a[i-1]  

如果 bi<=0 說明在完成i-1時可以順便把i位置完成

如果 bi>0 說明完成i-1後至少還需要bi才能完成

那麼我們維護兩個樹狀數組 

第一個樹狀數組維護的是差分數組 bi  第二個樹狀數組維護的是ci(ci=bi && bi>0) 

修改操作就是常規的差分數組修改 

詢問的話 就是 a_{l}+c_{l+1}+c_{l+2}.......+c_{r}

也就是 b_{1}+b_{2}+......+b_{l}+c_{l+1}+c_{l+2}+......c_{r}

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
typedef long long ll;
ll a[N],b[N];
ll p1[N],p2[N];
int n,m;
void add(int x,ll val,ll p[]){
	while(x<=n){
		p[x]+=val;
		x+=x&-x;
	}
}
ll query(int x,ll p[]){
	ll ret = 0;
	while(x){
		ret+=p[x];
		x-=x&-x;
	}
	return ret;
}
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		memset(p1,0,sizeof(p1));
		memset(p2,0,sizeof(p2));
		scanf("%d%d",&n,&m);
		for(int i = 1; i <= n; i++){
			scanf("%lld",&a[i]);
			b[i]=a[i]-a[i-1];
			add(i,b[i],p1);
			if(b[i]>0) add(i,b[i],p2);
		}
		for(int i = 1; i <= m; i++){
			int op,l,r,k;
			scanf("%d%d%d",&op,&l,&r);
			if(op==1){
				scanf("%d",&k);
				add(l,k,p1),add(r+1,-k,p1);
				if(b[l]>0) add(l,k,p2);
				else if(b[l]+k>0) add(l,b[l]+k,p2);
				if(b[r+1]>0){
					if(b[r+1]-k>0) add(r+1,-k,p2);
					else add(r+1,-b[r+1],p2);
				}
				b[l]+=k,b[r+1]-=k;
			}else{
				printf("%lld\n",query(l,p1)+query(r,p2)-query(l,p2));
			}
		}
	}
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章