线段树模板

 单纯的模板

区间求和 区间最值 区间加法 点加法

通过区间求和或区间最值 可以求点值

#include
using namespace std;
typedef long long ll;
ll a[100010];
struct T{
	ll lt,rt;
	ll sum,mx,mn,lazy;
}tr[400010];
void pushup(ll root){//向下传递 
	ll s1=root<<1,s2=root<<1|1;
	tr[root].sum=tr[s1].sum+tr[s2].sum;
	tr[root].mx=max(tr[s1].mx,tr[s2].mx);
	tr[root].mn=min(tr[s1].mn,tr[s2].mn);
}
void ct(ll g,ll l,ll r){//创建 
	tr[g].lt=l,tr[g].rt=r;
	if(l==r){tr[g].sum=a[l]; tr[g].mx=tr[g].mn=a[l]; return;}
	ll mid=(l+r)>>1;
	ct(g<<1,l,mid);
	ct(g<<1|1,mid+1,r);
	pushup(g);
}
void updata(ll g,ll pos,ll val){//将pos位置的值加上val 使用时配合a数组,记得更新a数组的值 
	if(tr[g].lt==tr[g].rt&&tr[g].lt==pos)
		{tr[g].sum+=val; tr[g].mx+=val; tr[g].mn+=val; return;}
	ll mid=(tr[g].lt+tr[g].rt)>>1;
	if(pos<=mid) updata(g<<1,pos,val);
	else updata(g<<1|1,pos,val);
	pushup(g);
}
ll qmx(ll g,ll x,ll y){//qmx[1,x,y] 取[x,y]的最大值
	if(tr[g].lt==x&&tr[g].rt==y) return tr[g].mx;
	ll mid=(tr[g].lt+tr[g].rt)>>1;
	if(y<=mid) return qmx(g<<1,x,y);
	else if(x>mid) return qmx(g<<1|1,x,y);
	else {ll a=qmx(g<<1,x,mid);ll b=qmx(g<<1|1,mid+1,y);return max(a,b);}
}
ll qmn(ll g,ll x,ll y){//qmn[1,x,y] 取[x,y]的最小值
	if(tr[g].lt==x&&tr[g].rt==y) return tr[g].mn;
	ll mid=(tr[g].lt+tr[g].rt)>>1;
	if(y<=mid) return qmn(g<<1,x,y);
	else if(x>mid) return qmn(g<<1|1,x,y);
	else{ll a=qmn(g<<1,x,mid);ll b=qmn(g<<1|1,mid+1,y);return min(a,b);}	
}
void change(ll h,ll l,ll r,ll s,ll e,ll k){
	if(l==s&&r==e){tr[h].lazy+=k; return;}
	tr[h].sum+=(e-s+1)*k;
	ll mid=(l+r)/2;
	if(s>=mid+1) change(h*2+1,mid+1,r,s,e,k);
	else if(e<=mid) change(h*2,l,mid,s,e,k);
	else {change(h*2,l,mid,s,mid,k);change(h*2+1,mid+1,r,mid+1,e,k);}
}
ll qsum(ll g,ll x,ll y){//qsum[1,x,y] 取[x,y]的和 
	if(tr[g].lt==x&&tr[g].rt==y) return tr[g].sum+tr[g].lazy*(tr[g].rt-tr[g].lt+1);
	ll mid=(tr[g].lt+tr[g].rt)>>1;
	ll ret=0;
	if(tr[g].lazy){
		tr[g].sum+=tr[g].lazy*(tr[g].rt-tr[g].lt+1);
		change(g*2,tr[g].lt,mid,tr[g].lt,mid,tr[g].lazy);
		change(g*2+1,mid+1,tr[g].rt,mid+1,tr[g].rt,tr[g].lazy);
		tr[g].lazy=0;
	}
	if(y<=mid)return qsum(g<<1,x,y);
	else if(x>mid)return qsum(g<<1|1,x,y);
	else{ret+=qsum(g<<1,x,mid); ret+=qsum(g<<1|1,mid+1,y); return ret;}
}
void qjup(int root, int nstart, int nend, int ustart, int uend, int addVal)
{//qjup(1,1,n,x,y,k) [x,y]区间内的数均加k 
    if(ustart > nend || uend < nstart) return ;
    if(ustart <= nstart && uend >= nend)
    {
        tr[root].sum += addVal;
        tr[root].mn += addVal;
        tr[root].mx += addVal;
        return ;
    }
   	pushup(root); 
    int mid = (nstart + nend) / 2;
    qjup(root*2, nstart, mid, ustart, uend, addVal);
    qjup(root*2+1, mid+1, nend, ustart, uend, addVal);
    
    tr[root].mn = min(tr[root*2].mn , tr[root*2+1].mn);
    tr[root].mx = max(tr[root*2].mx, tr[root*2+1].mx);
    tr[root].sum = tr[root*2].sum + tr[root*2+1].sum;
}

int main(){
	ll m,n;
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>a[i];//初始化a数组 
	ct(1,1,n);
	while(m--)
	{//各种命令 
		ll p,x,y,k;
		cin>>p>>x>>y;
		if(p==1) y 
		{
		//	updata(1,x,y-a[x]);//updata 更新x位置+
		//	qjup(1,1,n,x,x,y-a[x]);//
			a[x]=y;//及时更新a数组 
		}
		else if(p==2) cout<

 

你可能感兴趣的:(线段树)