BZOJ3211花神遊歷各國(小清新線段樹)

題目傳送門php


題目描述:html

花神喜歡步行遊歷各國,順便虐爆各地競賽。花神有一條遊覽路線,它是線型的,也就是說,全部遊歷國家呈一條線的形狀排列,花神對每一個國家都有一個喜歡程度(固然花神並不必定喜歡全部國家)。c++

每一次旅行中,花神會選擇一條旅遊路線,它在那一串國家中是連續的一段,此次旅行帶來的開心值是這些國家的喜歡度的總和,固然花神對這些國家的喜歡程序並非恆定的,有時會忽然對某些國家產生反感,使他對這些國家的喜歡度δ變爲δ​​(多是花神虐爆了那些國家的 OI,從而感到乏味)。函數

如今給出花神每次的旅行路線,以及開心度的變化,請求出花神每次旅行的開心值。ui


輸入格式:spa

第一行是一個整數N,表示有N個國家;
第二行有N個空格隔開的整數,表示每一個國家的初始喜歡度;
第三行是一個整數M,表示有M條信息要處理;
第四行到最後,每行三個整數想x,l,r,當x=1時詢問遊歷國家x到r的開心值總和,也就是Σδi(l~r)x=2時國家l到r中每一個國家的喜歡度δi變爲δi
htm


輸出格式:blog

每次x=1時,每行一個整數。表示此次旅行的開心度。遞歸


樣例:get

樣例輸入:

4
1 100 5 5
5
1 1 2
2 1 2
1 1 2
2 2 3
1 1 4

樣例輸出:

101
11
11


數據範圍與提示:

對於所有數據,1≤n≤105,1≤m≤2×105,1≤l≤r≤n,0≤δi≤109

注:建議使用sqrt函數,且向下取整。


一句話題意:線段樹區間開跟,區間求和。


 題解:

區間信息沒法快速更新,沒法使用延遲標記。(可怕)

可是注意,109最多開5次跟就不變了

那麼,每次修改暴力遞歸下去,直到當前區間已全是0或1就return

是否是很帥?


代碼時刻:

#include<bits/stdc++.h>
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
int n,m;
long long v[100001];
long long trsum[400001],trmax[400001];
void pushup(int x)
{
	trsum[x]=trsum[L(x)]+trsum[R(x)];
	trmax[x]=max(trmax[L(x)],trmax[R(x)]);
}
void build(int x,int l,int r)
{
	if(l==r)
	{
		trsum[x]=trmax[x]=v[l];
		return;
	}
	int mid=(l+r)>>1;
	build(L(x),l,mid);
	build(R(x),mid+1,r);
	pushup(x);
}
void change(int x,int l,int r,int L,int R)
{
	if(l==r)
	{
		trsum[x]=sqrt(trsum[x]);
		trmax[x]=sqrt(trmax[x]);
		return;
	}
	if(trmax[x]<=1)return;//注意這裏爲≤,其餘跟普通線段樹別無兩樣 
	int mid=(l+r)>>1;
	if(L<=mid)change(L(x),l,mid,L,R);
	if(R>mid)change(R(x),mid+1,r,L,R);
	pushup(x);
}
long long ask(int x,int l,int r,int L,int R)
{
	if(L<=l&&r<=R)return trsum[x];
	int mid=(l+r)>>1;
	long long rec=0;
	if(L<=mid)rec+=ask(L(x),l,mid,L,R);
	if(R>mid)rec+=ask(R(x),mid+1,r,L,R);
	return rec;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%lld",&v[i]);
	build(1,1,n);
	scanf("%d",&m);
	while(m--)
	{
		int op,l,r;
		scanf("%d%d%d",&op,&l,&r);
		if(op==1)printf("%lld\n",ask(1,1,n,l,r));
		else change(1,1,n,l,r);
	}
	return 0;
}

 cpp

rp++

相關文章
相關標籤/搜索