單點修改與查詢
//單點修改,區間詢問最小值 #include <iostream> #include <cstdio> #define maxn 101 #define INF 0x7fffffff using namespace std; int a[maxn],n,m; int mi[maxn]; void build(int k,int l,int r)//k是當前節點編號,l,r為當前節點代表區間 { if(l==r) { mi[k]=a[l]; return; } int mid=(l+r)/2; build(k*2,l,mid);//左子樹 build(k*2+1,mid+1,r);//右子樹 mi[k]=min(mi[2*k],mi[2*k+1]);//維護最小值 }//建立線段樹 int query(int k,int l,int r,int x,int y)//x,y為詢問區間,l,r為當前區間 { if(y<l||x>r)return INF;//詢問區間與當前區間完全無交集 if(x<=l&&y>=r) { return mi[k]; }//詢問區間完全包含當前區間 int mid=(l+r)/2; return min(query(k*2,l,mid,x,y),query(k*2+1,mid+1,r,x,y));//否則分別處理左右子樹 } void update(int k,int l,int r,int x,int v)//x為原序列位置,v為要修改的值 { if(r<x||l>x)return; //當前區間與原序列位置完全無交集 if(l==r&&l==x)//當前節點為葉子結點 { mi[k]=v;//修改葉子結點 return; } int mid=(l+r)/2; update(k*2,l,mid,x,v); update(k*2+1,mid+1,r,x,v); mi[k]=min(mi[k*2],mi[k*2+1]); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); } build(1,1,n); for(int i=1;i<=m;i++) { int k,l,r; scanf("%d%d%d",&k,&l,&r); if(k==0)//更新 { update(1,1,n,l,r); } if(k==1) { int ans=query(1,1,n,l,r); printf("%d\n",ans); } } return 0; }
區間修改與查詢
注意要使用標記下傳來實現。
//線段樹-區間修改,查詢區間和 #include <iostream> #include <cstdio> #define ll long long #define maxn 1000005 using namespace std; ll sum[maxn];//序號為k的區間的區間和 ll a[maxn]; ll add[maxn];//lazy標記 int n,m; void build(int k,int l,int r) { if(l==r) { sum[k]=a[l]; return; } int mid=(l+r)/2; build(2*k,l,mid); build(2*k+1,mid+1,r); sum[k]=sum[2*k]+sum[2*k+1]; }//建立線段樹,維護區間和 void Add(int k,int l,int r,ll v)//給定區間[l,r]所有數加上v(打標記) { add[k]+=v; sum[k]+=(r-l+1)*v;//維護區間和 return; } void pushdown(int k,int l,int r,int mid)//標記下傳 { if(add[k]==0)return; Add(k*2,l,mid,add[k]);//下傳到左子樹 Add(k*2+1,mid+1,r,add[k]);//下傳到右子樹 add[k]=0; //清零標記 } void modify(int k,int l,int r,int x,int y,ll v)//給區間[x,y]所有的數加上v(真的加上) { if(l>=x&&r<=y) { return Add(k,l,r,v); } int mid=(l+r)/2; pushdown(k,l,r,mid); //到達每一個結點都要下傳標記 if(x<=mid)modify(2*k,l,mid,x,y,v);//修改左子樹 if(y>mid)modify(2*k+1,mid+1,r,x,y,v);//修改右子樹 sum[k]=sum[2*k]+sum[2*k+1]; } ll query(int k,int l,int r,int x,int y) { if(l>=x&&r<=y) { return sum[k]; } int mid=(l+r)/2; ll res=0; pushdown(k,l,r,mid); if(x<=mid) { res+=query(k*2,l,mid,x,y); } if(y>mid) { res+=query(k*2+1,mid+1,r,x,y); } return res; }//詢問區間[x,y]的區間和 int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); } build(1,1,n); for(int i=1;i<=m;i++) { int op,l,r; scanf("%d%d%d",&op,&l,&r); if(op==1) { ll v; scanf("%lld",&v); modify(1,1,n,l,r,v); } if(op==2) { ll ans=query(1,1,n,l,r); printf("%lld\n",ans); } } return 0; }