普通的线段树也能写,只是练习一下zkw线段树。
// POJ 3468
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const int maxn=100000+10;
int n,bit,q;
ll sum[maxn<<2],add[maxn<<2];
// 带输入的init
void init(){
bit=1;
while (bit<=n+1) bit<<=1;
memset(add,0,sizeof(add));
for (int i=bit+1;i<=bit+n;i++) scanf("%lld",&sum[i]);
sum[bit]=0;
for (int i=bit+n+1;i<=bit+bit-1;i++) sum[i]=0;
for (int i=bit-1;i;i--) sum[i]=sum[i<<1]+sum[i<<1|1];
}
// 区间求和
ll query(int l,int r){
int ln=0,rn=0,x=1; // 左右分支已加的点数和每树元素个数
ll ans=0;
for (l+=bit-1,r+=bit+1;l^r^1;l>>=1,r>>=1,x<<=1){
// 先读取标记的更新
if (add[l]) ans+=add[l]*ln;
if (add[r]) ans+=add[r]*rn;
// 再常规求和
if (~l&1) ans+=sum[l^1]+x*add[l^1],ln+=x;
if (r&1) ans+=sum[r^1]+x*add[r^1],rn+=x;
}
// 处理同层的情况
if (add[l]) ans+=add[l]*ln;
if (add[r]) ans+=add[r]*rn;
ln+=rn;
l>>=1;
// 处理上层的情况
for (;l^1;l>>=1){
if (add[l])
ans+=add[l]*ln;
}
return ans;
}
// 区间加v
void increase(int l,int r,int v){
int ln=0,rn=0,x=1;
for (l+=bit-1,r+=bit+1;l^r^1;l>>=1,r>>=1,x<<=1){
// 先更新sum
sum[l]+=1ll*v*ln;
sum[r]+=1ll*v*rn;
// 再更新add
if (~l&1) add[l^1]+=v,ln+=x;
if (r&1) add[r^1]+=v,rn+=x;
}
// 处理同层的情况
sum[l]+=1ll*v*ln;
sum[r]+=1ll*v*rn;
ln+=rn;
l>>=1;
// 处理上层的情况
for (;l^1;l>>=1) sum[l]+=1ll*v*ln;
}
char op[2];
int main(){
scanf("%d %d",&n,&q);
init();
while (q--){
scanf("%s",op);
if (op[0]=='Q'){
int a,b;
scanf("%d %d",&a,&b);
printf("%lld\n",query(a,b));
}
else{
int a,b,c;
scanf("%d %d %d",&a,&b,&c);
increase(a,b,c);
}
}
}
// cf 52c
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
int bit,n,q;
ll tree[maxn<<2];
char str[100];
void build(int n){
for (bit=1;bit<=n+1;bit<<=1);
for (int i=bit+1;i<=bit+n;i++) scanf("%lld",&tree[i]);
for (int i=bit-1;i;i--) tree[i]=min(tree[i<<1],tree[i<<1|1]);
for (int i=bit+n;i;i--) tree[i]=tree[i]-tree[i >> 1];
}
void update(int l,int r,int x){
ll tmp;
for (l=l+bit-1,r=r+bit+1;l^r^1;l>>=1,r>>=1){
if (~l&1) tree[l^1]+=x;
if (r&1) tree[r^1]+=x;
tmp=min(tree[l],tree[l^1]),tree[l]-=tmp,tree[l^1]-=tmp,tree[l>>1]+=tmp;
tmp=min(tree[r],tree[r^1]),tree[r]-=tmp,tree[r^1]-=tmp,tree[r>>1]+=tmp;
}
while(l>1) tmp=min(tree[l],tree[l^1]),tree[l]-=tmp,tree[l^1]-=tmp,tree[l>>=1]+=tmp;
}
ll query(int l,int r){
l+=bit,r+=bit;
ll lans=0,rans=0;
if (l!=r){
for (;l^r^1;l>>=1,r>>=1){
lans+=tree[l],rans+=tree[r];
if(~l&1) lans=min(lans,tree[l^1]);
if(r&1) rans=min(rans,tree[r^1]);
}
}
ll ans=min(lans+tree[l],rans+tree[r]);
while (l>1) ans+=tree[l>>=1];
return ans;
}
vector <int> cal(char s[],int len){
vector <int> vec;
bool flag=0;
int ans=0;
for (int i=0;i<len;i++){
if (s[i]==' '||s[i]=='\0'){
if (flag) ans=-ans;
vec.push_back(ans);
ans=0;
flag=0;
}
else if (s[i]=='-'){
flag=1;
}
else{
ans=ans*10+s[i]-'0';
}
}
if (flag) ans=-ans;
vec.push_back(ans);
return vec;
}
int main(){
scanf("%d",&n);
build(n);
scanf("%d",&q);
getchar();
while (q--){
cin.getline(str,99);
int len=strlen(str);
vector <int> tmp=cal(str,len);
int sz=tmp.size();
if (sz==3){
int l=tmp[0],r=tmp[1],v=tmp[2];
l++,r++;
if (l>r){
update(1,r,v);
update(l,n,v);
}
else update(l,r,v);
}
else if (sz==2){
int l=tmp[0],r=tmp[1];
l++,r++;
ll ans=1e18;
if (l>r) ans=min(query(1,r),query(l,n));
else ans=query(l,r);
printf("%lld\n",ans);
}
}
}