线段树
懒标记的修改时间和下传时间:
wa:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstdlib>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=1e6+5;
const int INF=2147483647;
inline int read(){
int a=0;bool b=1;char x=getchar();
while(x<'0'||'9'<x){
if(x=='-')b=0;
x=getchar();
}
while('0'<=x&&x<='9'){
a=(a<<1)+(a<<3)+x-'0';
x=getchar();
}
return b ? a : -a ;
}
int n,m,a[maxn];
struct Node{
int l;int r;LL sum;LL addsum;
inline void deal(){
sum+=addsum*(r-l+1);
addsum=0ll;
return;
}
inline void print(){
printf("%d %d %lld %lld\n",l,r,sum,addsum);
return;
}
}L[maxn*4];
inline void down(int k){
if(L[k].l!=L[k].r){
L[k<<1].addsum+=L[k].addsum;
L[(k<<1)+1].addsum+=L[k].addsum;
}
L[k].deal();
return;
}
void build(int k,int l,int r){
if(l==r)L[k]={l,r,a[l]};
else{
int mid=(l+r)>>1;
build((k<<1),l,mid);
build((k<<1)+1,mid+1,r);
L[k]={l,r,L[(k<<1)].sum+L[(k<<1)+1].sum};
}
}
void modify(int k,int l,int r,int x){
if(l<=L[k].l&&L[k].r<=r){
L[k].print();
L[k].addsum+=(LL)x;
down(k);
L[k].print();
}
else{
int mid=(L[k].l+L[k].r)>>1;
LL add1=0ll,add2=0ll;
if(l<=mid){
add1=L[k<<1].sum;
modify((k<<1),l,r,x);
add1=L[k<<1].sum-add1;
}
if(mid<r){
add2=L[(k<<1)+1].sum;
modify((k<<1)+1,l,r,x);
add2=L[(k<<1)+1].sum-add2;
}
L[k].sum+=(add1+add2);
//叶子节点保证必须是对的,有时候会有问题
//懒标记不能重复加,修改完一个区间,其子节点的懒标记在下次修改时不能更新自己
}
}
LL query(int k,int l,int r){
if(L[k].addsum)down(k);
//保证每次遇到的节点都是最新的
L[k].print();
L[12].print();
if(l<=L[k].l&&L[k].r<=r)return L[k].sum;
int mid=(L[k].l+L[k].r)>>1;
LL ans=0ll;
if(l<=mid)ans+=query((k<<1),l,r);
if(mid<r)ans+=query((k<<1)+1,l,r);
return ans;
}
int main(){
freopen("1.out","w",stdout);
n=read();
for(int i=1;i<=n;i++)a[i]=read();
build(1,1,n);
m=read();
for(int i=1,b,l,r,x;i<=m;i++){
b=read();
if(b==1){
l=read();r=read();x=read();
modify(1,l,r,x);
}
else{
l=read();r=read();
printf("%lld\n",query(1,l,r));
}
}
return 0;
}
/*
10
1 2 3 4 5 6 1 2 3 4
4 4
5 5 5 5 5
5 5 5 5 5
5
1 2 3 4
2 1 4
1 3 7 5
1 2 6 5
2 1 7
*/
模板:
#include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<cmath> using namespace std; const int maxn=6e4+5; template <typename T> inline void read(T &a){ a=0;T b=1;char x=getchar(); while(x<'0'||'9'<x){ if(x=='-')b=-1; x=getchar(); } while('0'<=x && x<='9'){ a=(a<<1)+(a<<3)+x-'0'; x=getchar(); } a*=b; } char ch[30]; int temp; template <typename T> inline void print(T a){ if(a<0){ putchar('-'); a=-a; } do{ ch[++temp]= a % 10 + '0'; a /= 10; }while(a); while(temp) putchar(ch[temp--]);putchar(' '); } template <typename T> struct Node { int l;int r;T sum;T Min;T Max;T lazy; inline void update(const Node &a,const Node &b){ sum=a.sum+b.sum; Min=min(a.Min,b.Min); Max=max(a.Max,b.Max); } inline void add(T x){ sum+=(r-l+1)*x;Min+=x;Max+=x; lazy+=x; } inline void Print(){ print(sum);print(Min);print(Max);putchar('\n'); } }; int n,m,a[maxn]; template <typename T> class Segment_tree { public: Node<T> L[maxn*4]; inline void pushdown(int k){ L[k<<1].add(L[k].lazy); L[k<<1|1].add(L[k].lazy); L[k].lazy=0; } Node<T> query(int k,int l,int r){ if(l<=L[k].l&&L[k].r<=r){ return L[k]; } else{ pushdown(k); int mid=(L[k].l+L[k].r)>>1; if(r<=mid)return query(k<<1,l,r); if(mid<l)return query(k<<1|1,l,r); Node <T>ans; ans.update(query(k<<1,l,r),query(k<<1|1,l,r)); return ans; } } void build(int k,int l,int r){ if(l==r){ L[k]={l,r,a[l],a[l],a[l]}; return; } else{ int mid=(l+r)>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); L[k]={l,r}; return L[k].update(L[k<<1],L[k<<1|1]); } } void modify(int k,int l,int r,T x){ if(l<=L[k].l&&L[k].r<=r){ return L[k].add(x); } else{ pushdown(k); int mid=(L[k].l+L[k].r)>>1; if(l<=mid) modify(k<<1,l,r,x); if(mid<r) modify(k<<1|1,l,r,x); return L[k].update(L[k<<1],L[k<<1|1]); } } }; Segment_tree<int > s; int main(){ read(n); for(int i=1;i<=n;i++){ read(a[i]); } s.build(1,1,n); read(m); for(int i=1,b,x,y,z;i<=m;i++){ read(b); if(!b){ read(x);read(y);read(z); s.modify(1,x,y,z); } else{ read(x);read(y); s.query(1,x,y).Print(); } } return 0; }
灵活使用线段树:
不一定非得标记下传,不一定非得区间合并,注意计算复杂度
#include<cstdio> #include<algorithm> #include<cmath> #define LL long long using namespace std; const int maxn=1e5+5; template<typename T> inline void read(T &a){ //!! 引用 a=0;T b=1;char x=getchar(); while(x<'0' || '9'<x){ if(x=='-')b=-1; x=getchar(); } while('0'<=x&&x<='9'){ a=(a<<1)+(a<<3)+x-'0'; x=getchar(); } a*=b; } char ch[30]; int temp; template<typename T> inline void print(T a){ if(a<0){ putchar('-'); a=-a; } do{ ch[++temp]=a%10+'0'; a/=10; }while(a); while(temp)putchar(ch[temp--]);putchar('\n'); } int n,m; LL a[maxn]; struct Node{ int l;int r;LL sum;bool judge; //问题特性:几次运算之后就会无法变化&当前节点难以直接算出 inline void update(const Node&a,const Node&b){ sum=a.sum+b.sum; judge=a.judge & b.judge; } inline void Print(){ print(l);print(r);print(sum);print(judge); } }L[maxn*4]; inline void build(int k,int l,int r){ if(l==r){ L[k]={l,r,a[l],a[l]==1ll}; } else{ int mid=(l+r)>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); L[k]={l,r}; L[k].update(L[k<<1],L[k<<1|1]);//L[k].Print();putchar('\n'); } } /*inline void pushdown(int k) { L[k<<1].modify(L[k].lazy); L[k<<1|1].modify(L[k].lazy); L[k].lazy=0; }*/ //本题为标记上传,标记下传很麻烦 LL query(int k,int l,int r){ if(l<=L[k].l&&L[k].r<=r){ return L[k].sum; } else{ //if(L[k].lazy)pushdown(k); int mid=(L[k].l+L[k].r)>>1; LL ans=0; if(l<=mid)ans+=query(k<<1,l,r); if(mid<r)ans+=query(k<<1|1,l,r); return ans; } } void modify(int k,int l,int r){ if(L[k].judge)return; //all is one ,needn‘t changing if(L[k].l==L[k].r){ L[k].sum=sqrt(L[k].sum); if(L[k].sum==1ll)L[k].judge=1; //修改要都修改,否则吃屎!!!三处使用,只修改两处,瞬间傻B!!! } else{ int mid=(L[k].l+L[k].r)>>1; if(r<=mid)modify(k<<1,l,r); else if(mid<l)modify(k<<1|1,l,r); else { modify(k<<1,l,r); modify(k<<1|1,l,r); } L[k].update(L[k<<1],L[k<<1|1]); //L[k].Print(); } } /*int f[maxn]; int find(int x){return x==f[x] ? x : f[x]=find(f[x]) ;}*/ int main(){ read(n); for(int i=1;i<=n;i++){ read(a[i]); //f[i]=i; } build(1,1,n); read(m); for(int i=1,k,l,r;i<=m;i++){ read(k);read(l);read(r); if(l>r)swap(l,r); if(!k){ modify(1,l,r); } else{ print(query(1,l,r)); } } return 0; }