[模板]線段樹
阿新 • • 發佈:2019-01-25
1、注意程式碼是左閉右閉的線段樹,mid在左區間內
2、打權值線段樹時注意線段樹右端點大於最大值
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define L(w) w << 1
#define R(w) w << 1|1
#define INF 1061109567
typedef long long LL;
using namespace std;
const int MAXN = 200000 + 50;
int L[MAXN << 2 ],R[MAXN << 2],maxn[MAXN << 2],minx[MAXN << 2],M1[MAXN << 2],M2[MAXN << 2];
LL sum[MAXN << 2];
int A[MAXN];
void update(int w){
sum[w] = sum[L(w)] + sum[R(w)];
minx[w] = min(minx[L(w)],minx[R(w)]);
maxn[w] = max(maxn[L(w)],maxn[R(w)]);
}
void spread1(int w){
if(M1[w] == -1)return;
int m = M1[w];
M1[w] = -1;
minx[L(w)] = maxn[L(w)] = m;
minx[R(w)] = maxn[R(w)] = m;
sum[L(w)] = m*(R[L(w)] - L[L(w)] + 1);
sum[R(w)] = m*(R[R(w)] - L[R(w)] + 1);
M2[L(w)] = M2[R(w)] = 0;
M1[L(w)] = M1[R(w)] = m;
}
void spread(int w){
if (M1[w] != -1){
spread1(w);
}
int m = M2[w];
if(!m)return;
M2[w] = 0;
spread1(L(w));
spread1(R(w));
maxn[L(w)] += m;
maxn[R(w)] += m;
minx[L(w)] += m;
minx[R(w)] += m;
sum[L(w)] += m*(R[L(w)] - L[L(w)] + 1);
sum[R(w)] += m*(R[R(w)] - L[R(w)] + 1);
M2[L(w)] += m;
M2[R(w)] += m;
}
void build(int w,int l,int r){
L[w] = l;R[w] = r;
if(l == r){
sum[w] = minx[w] = maxn[w] = A[l];
return;
}
int mid = l + r >> 1;
build(L(w),l,mid);
build(R(w),mid + 1,r);
update(w);
}
void cover(int w,int l,int r,int v){
if(L[w] == l && R[w] == r){
M2[w] = 0;
M1[w] = v;
minx[w] = maxn[w] = v;
sum[w] = v*(R[w] - L[w] + 1);
return;
}
spread(w);//重置前,先下放標記
int mid = L[w] + R[w] >> 1;
if(r <= mid)cover(L(w),l,r,v);
else if(l > mid)cover(R(w),l,r,v);
else cover(L(w),l,mid,v),cover(R(w),mid + 1,r,v);
update(w);
}
void add(int w,int l,int r,int v){
if(L[w] == l && R[w] == r){
spread1(w);
M2[w] += v;
minx[w] += v;
maxn[w] += v;
sum[w] += v*(R[w] - L[w] + 1);
return;
}
spread(w);
int mid = L[w] + R[w] >> 1;
if(r <= mid)add(L(w),l,r,v);
else if(l > mid)add(R(w),l,r,v);
else add(L(w),l,mid,v),add(R(w),mid + 1,r,v);
update(w);
}
LL ask_sum(int w,int l,int r){
if(L[w] == l && R[w] == r){
return sum[w];
}
spread(w);
LL ans = 0;
int mid = L[w] + R[w] >> 1;
if(r <= mid)ans = ask_sum(L(w),l,r);
else if(l > mid)ans = ask_sum(R(w),l,r);
else ans = ask_sum(L(w),l,mid) + ask_sum(R(w),mid + 1,r);
return ans;
}
int ask_max(int w,int l,int r){
if(L[w] == l && R[w] == r){
return maxn[w];
}
spread(w);
int mid = L[w] + R[w] >> 1;
int ans = -INF;
if(r <= mid)ans = ask_max(L(w),l,r);
else if(l > mid)ans = ask_max(R(w),l,r);
else ans = max(ask_max(L(w),l,mid),ask_max(R(w),mid + 1,r));
return ans;
}
int ask_min(int w,int l,int r){
if(L[w] == l && R[w] == r){
return minx[w];
}
spread(w);
int mid = L[w] + R[w] >> 1;
int ans = INF;
if(r <= mid)ans = ask_min(L(w),l,r);
else if(l > mid)ans = ask_min(R(w),l,r);
else ans = min(ask_min(L(w),l,mid),ask_min(R(w),mid + 1,r));
return ans;
}
int n,m,a,b,c;
string s;
int main(){
memset(M1,-1,sizeof(M1));
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 ++){
cin >> s;
if(s == "add"){
scanf("%d%d%d",&a,&b,&c);
add(1,a,b,c);
}
else if(s == "set"){
scanf("%d%d%d",&a,&b,&c);
cover(1,a,b,c);
}
else if(s == "sum"){
scanf("%d%d",&a,&b);
if(a > b)swap(a,b);
printf("%lld\n",ask_sum(1,a,b));
}
else if(s == "max"){
scanf("%d%d",&a,&b);
printf("%d\n",ask_max(1,a,b));
}
else if(s == "min"){
scanf("%d%d",&a,&b);
printf("%d\n",ask_min(1,a,b));
}
}
return 0;
}