P3372 【模板】线段树 1

                                    P3372 【模板】线段树 1

 线段树

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+7;
int n,m;
long long a[MAXN],tree[MAXN*4],lazy[MAXN*4];
//tree[] 最大是4*MAXN 
//lazy[] 标记 其子节点待加lazy[],保证复杂度小于O(n) 

void up(int root){  //向上传递更新 
	tree[root]=tree[root<<1]+tree[root<<1 | 1];
}

void down(int root,int l,int r){ //*** 向下更新tree[root<<1]和tree[root<<1 | 1] ,传递lazy[] 
	if(lazy[root]){
		int mid=(l+r)>>1;
		tree[root<<1]+=lazy[root]*(mid-l+1);
		tree[root<<1 | 1]+=lazy[root]*(r-mid);
		lazy[root<<1]+=lazy[root];
		lazy[root<<1 | 1]+=lazy[root];
		lazy[root]=0;
	}
}

void build(int root,int l,int r){//建树 
	if(l==r){
		tree[root]=a[l];
		lazy[root]=0;//***赋初值,不然会错 
		return;
	}
	int mid=(l+r)>>1;
	down(root,l,r);//更新不能忘 
	build(root<<1,l,mid);
	build((root<<1)+1,mid+1,r);
	up(root);// 更新不能忘
}

void add(int root,int l,int r,int ql,int qr,long long x){
	if(l>=ql&&r<=qr){
		tree[root]+=x*(r-l+1);
		lazy[root]+=x;
		return;
	}
	int mid=(l+r)>>1;
	down(root,l,r);//更新不能忘,步步更新 
	if(ql<=mid) add(root<<1,l,mid,ql,qr,x);
	if(qr>mid)  add(root<<1 | 1,mid+1,r,ql,qr,x);
	up(root);//更新不能忘,步步更新 
}

long long getsum(int root,int l,int r,int ql,int qr){
	if(l>=ql&&r<=qr){
		return tree[root];
	}
	int mid=(l+r)>>1;
	long long res=0;
	down(root,l,r);//步步更新  
	if(ql<=mid) res+=getsum(root<<1,l,mid,ql,qr);
	if(qr>mid) res+=getsum(root<<1 | 1,mid+1,r,ql,qr);
	up(root);//步步更新 
	return res;
}
int main(){
	ios::sync_with_stdio(false);
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	build(1,1,n);
	for(int i=1;i<=m;i++){
		int op,x,y;
		long long k;
		cin>>op;
		if(op==1){
			cin>>x>>y>>k;
			add(1,1,n,x,y,k);
		}
		if(op==2){
			cin>>x>>y;
			cout<<getsum(1,1,n,x,y)<<"\n";
		}
	}
}

 树状数组 :差分+2个树状数组

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+7;
int n,m;
long long a[MAXN],ch[MAXN],tree_1[MAXN],tree_2[MAXN];

long long lowbit(long long x){
	return x&(-x);
}

long long tree_1_notadd(int pos){
	long long res=0;
	while(pos>0){
		res+=tree_1[pos];
		pos-=lowbit(pos);
	}
	return res;
}

void tree_1_add(int pos,long long x){
	while(pos<=n){
		tree_1[pos]+=x;
		pos+=lowbit(pos);
	}
}
long long tree_2_notadd(int pos){
	long long res=0;
	while(pos>0){
		res+=tree_2[pos];
		pos-=lowbit(pos);
	}
	return res;
}

void tree_2_add(int pos,long long x){
	while(pos<=n){
		tree_2[pos]+=x;
		pos+=lowbit(pos);
	}
}
int main(){
	ios::sync_with_stdio(false);
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	ch[1]=a[1];
	tree_1_add(1,ch[1]);
	tree_2_add(1,ch[1]);
	for(int i=2;i<=n;i++){
		ch[i]=a[i]-a[i-1];
		tree_1_add(i,ch[i]);
		tree_2_add(i,ch[i]*i);
	}
	while(m--){
		int op;
		long long k;
		int x,y;
		cin>>op;
		if(op==1){
			cin>>x>>y>>k;
			tree_1_add(x,k);
			tree_1_add(y+1,-k);
			tree_2_add(x,1ll*k*x);
			tree_2_add(y+1,1ll*-k*(y+1));
		} 
		if(op==2){
			cin>>x>>y;
			long long high=1ll*(y+1)*tree_1_notadd(y)-tree_2_notadd(y);
			long long low=1ll*(x)*tree_1_notadd(x-1)-tree_2_notadd(x-1);
			cout<<high-low<<"\n";
			//cout<<1<<"\n";
		}
	}
}

加油!! 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ACM线段树模板C ```c #include<bits/stdc++.h> using namespace std; const int N=1e5+5;//数组开大一点 int n,m; int a[N]; struct node{ int l,r;//左右端点 int sum,lazy;//区间和和懒标记 }t[N*4]; void up(int p){//向上更新 t[p].sum=t[p<<1].sum+t[p<<1|1].sum; } void down(int p){//向下更新 if(t[p].lazy){ t[p<<1].lazy+=t[p].lazy; t[p<<1|1].lazy+=t[p].lazy; t[p<<1].sum+=t[p].lazy*(t[p<<1].r-t[p<<1].l+1); t[p<<1|1].sum+=t[p].lazy*(t[p<<1|1].r-t[p<<1|1].l+1); t[p].lazy=0; } } void build(int p,int l,int r){//建树 t[p].l=l,t[p].r=r; if(l==r){ t[p].sum=a[l]; return; } int mid=(l+r)/2; build(p<<1,l,mid); build(p<<1|1,mid+1,r); up(p); } void change(int p,int l,int r,int k){//单点修改 if(t[p].l==t[p].r){ t[p].sum=k; return; } down(p); int mid=(t[p].l+t[p].r)/2; if(r<=mid) change(p<<1,l,r,k); else if(l>mid) change(p<<1|1,l,r,k); else{ change(p<<1,l,mid,k); change(p<<1|1,mid+1,r,k); } up(p); } void add(int p,int l,int r,int k){//区间修改 if(t[p].l>=l&&t[p].r<=r){ t[p].sum+=k*(t[p].r-t[p].l+1); t[p].lazy+=k; return; } down(p); int mid=(t[p].l+t[p].r)/2; if(l<=mid) add(p<<1,l,r,k); if(r>mid) add(p<<1|1,l,r,k); up(p); } int query(int p,int l,int r){//区间查询 if(t[p].l>=l&&t[p].r<=r) return t[p].sum; down(p); int mid=(t[p].l+t[p].r)/2,ans=0; if(l<=mid) ans+=query(p<<1,l,r); if(r>mid) ans+=query(p<<1|1,l,r); return ans; } int main(){ cin>>n>>m; for(int i=1;i<=n;i++) cin>>a[i]; build(1,1,n); for(int i=1;i<=m;i++){ int opt,x,y,k; cin>>opt; if(opt==1){ cin>>x>>y>>k; add(1,x,y,k); } if(opt==2){ cin>>x>>y; cout<<query(1,x,y)<<endl; } if(opt==3){ cin>>x>>k; change(1,x,x,k); } } return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值