线段树『模板+例题』
模板
以 区间和 为例。
ll ls(ll p) {return p<<1;} ll rs(ll p) {return p<<1|1;} void push_up(ll p) { ans[p]=ans[ls(p)]+ans[rs(p)]; } void build(ll p,ll l,ll r) { tag[p]=0; if(l==r) {ans[p]=a[l]; return ;} ll Mid=(l+r)>>1; build(ls(p),l,Mid); build(rs(p),Mid+1,r); push_up(p); } void f(ll p,ll l,ll r,ll k) { tag[p]=tag[p]+k; ans[p]=ans[p]+k*(r-l+1); } void push_down(ll p,ll l,ll r) { ll Mid=(l+r)>>1; f(ls(p),l,Mid,tag[p]); f(rs(p),Mid+1,r,tag[p]); tag[p]=0; } void update(ll nl,ll nr,ll p,ll l,ll r,ll k) { if(nl<=l&&r<=nr) { tag[p]+=k; ans[p]+=k*(r-l+1); return ; } push_down(p,l,r); ll Mid=(l+r)>>1; if(nl<=Mid) update(nl,nr,ls(p),l,Mid,k); if(nr>Mid) update(nl,nr,rs(p),Mid+1,r,k); push_up(p); } ll query(ll ql,ll qr,ll p,ll l,ll r) { ll res=0; if(ql<=l&&r<=qr) return ans[p]; ll Mid=(l+r)>>1; push_down(p,l,r); if(ql<=Mid) res+=query(ql,qr,ls(p),l,Mid); if(qr>Mid) res+=query(ql,qr,rs(p),Mid+1,r); return res; }
例题
上帝造题的七分钟2 / 花神游历各国
分析
因为数列中的数$\le 10^{12}$,所以最多开方$6$次就可变为$1$。
当一个数已经等于$0$或$1$时,再开方就没有意义了(值不变)。
因此当线段树中某个叶子节点的值为$0$或$1$时,就给它打标记,可以不再操作。
同样,某个父亲节点的两个子节点都被标记时,也给它打标记。
详情见代码
1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 const int N=1e5+5; 5 int n,m; 6 ll a[N],sum[N<<2]; 7 bool tag[N<<2]; 8 inline ll read() { 9 ll x=0; char c=getchar(); 10 while(c<'0'||c>'9') c=getchar(); 11 while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=getchar(); 12 return x; 13 } 14 15 inline int ls(int p) {return p<<1;} 16 inline int rs(int p) {return p<<1|1;} 17 void push_up(int p) { 18 sum[p]=sum[ls(p)]+sum[rs(p)]; 19 tag[p]=tag[ls(p)]&&tag[rs(p)]; 20 } 21 void build(int p,int l,int r) { 22 if(l==r) {sum[p]=a[l]; return ;} 23 int Mid=(l+r)>>1; 24 build(ls(p),l,Mid); 25 build(rs(p),Mid+1,r); 26 push_up(p); 27 } 28 void update(int nl,int nr,int p,int l,int r) { 29 if(tag[p]) return ; 30 if(l==r) { 31 sum[p]=sqrt(sum[p]); 32 if(sum[p]==0||sum[p]==1) tag[p]=1; 33 return ; 34 } 35 int Mid=(l+r)>>1; 36 if(nl<=Mid) update(nl,nr,ls(p),l,Mid); 37 if(Mid<nr) update(nl,nr,rs(p),Mid+1,r); 38 push_up(p); 39 } 40 ll query(int ql,int qr,int p,int l,int r) { 41 ll res=0; 42 if(ql<=l&&r<=qr) return sum[p]; 43 int Mid=(l+r)>>1; 44 if(ql<=Mid) res+=query(ql,qr,ls(p),l,Mid); 45 if(Mid<qr) res+=query(ql,qr,rs(p),Mid+1,r); 46 return res; 47 } 48 49 int main() { 50 n=read(); 51 for(int i=1;i<=n;i++) a[i]=read(); 52 build(1,1,n); 53 m=read(); 54 while(m--) { 55 int k=read(),l=read(),r=read(); 56 if(l>r) swap(l,r); 57 if(k==0) update(l,r,1,1,n); 58 else printf("%lld\n",query(l,r,1,1,n)); 59 } 60 }
如有错误请指正。