線段樹略解
阿新 • • 發佈:2018-11-26
線段樹,一種極簡單的資料結構qaq
實際思想和分塊差不多,我們用一個栗子來簡單說一下線段樹:
考試之後老師說一樓一號教室的人都加五分
珂以直接貼一個條子在這個教室門上表示這個教室裡的人都加5分
校長又說1樓的所有人再加5分
那麼珂以直接在這層樓樓梯口處貼一張條子表示把所有在這層樓的人加5分
當你詢問一樓一號教室同學小a的成績時
我們到了一樓樓梯口
發現整層樓要加5分
先把這層樓每個教室的門口都貼上加5分的條子,再把樓梯口的撤掉(這是等價的)
我們到了一號教室門口
發現整個教室都要加10(5+5)分
先給每個人的成績加10分,再把門口的條子撤掉
最後就能查到小a的成績
這就是線段樹基本思想
線段樹的結構:
--------
---- ----
-- -- -- --
- - - - - - - -
線段樹就是要打標記來減少一些不必要的操作
每次操作為O(log n)
總複雜度O(m log n)
(n為總長度,m為查詢數量)
Luogu P3372 【模板】線段樹 1
完整程式碼(根據上方思想自己理解):
#include <bits/stdc++.h> #define ll long long #define N 100005 using namespace std; inline ll read() { register ll x=0,f=1;register char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return x*f; } inline void write(register ll x) { if(!x)putchar('0');if(x<0)x=-x,putchar('-'); static int sta[36];int tot=0; while(x)sta[tot++]=x%10,x/=10; while(tot)putchar(sta[--tot]+48); } ll val[N]; ll sum[N<<3]; ll tag[N<<3]; inline void pushup(register int x) { sum[x]=sum[x<<1]+sum[x<<1|1]; } inline void build(register int x,register int l,register int r) { if(l==r) { sum[x]=val[l]; tag[x]=0; return; } int mid=l+r>>1; build(x<<1,l,mid); build(x<<1|1,mid+1,r); pushup(x); } inline void pushdown(register int x,register int l,register int r) { int ls=x<<1,rs=x<<1|1,mid=l+r>>1; sum[ls]+=(mid-l+1)*tag[x]; sum[rs]+=(r-mid)*tag[x]; tag[ls]+=tag[x]; tag[rs]+=tag[x]; tag[x]=0; } inline void change(register int x,register int l,register int r,register int L,register int R,register int k) { if(L<=l&&r<=R) { sum[x]+=(r-l+1)*k; tag[x]+=k; return; } if(tag[x]) pushdown(x,l,r); int mid=l+r>>1; if(L<=mid) change(x<<1,l,mid,L,R,k); if(R>=mid+1) change(x<<1|1,mid+1,r,L,R,k); pushup(x); } inline ll query(register int x,register int l,register int r,register int L,register int R) { if(L<=l&&r<=R) return sum[x]; if(tag[x]) pushdown(x,l,r); ll res=0; int mid=l+r>>1; if(L<=mid) res+=query(x<<1,l,mid,L,R); if(R>=mid+1) res+=query(x<<1|1,mid+1,r,L,R); return res; } int main() { int n=read(),m=read(); for(register int i=1;i<=n;++i) val[i]=read(); build(1,1,n); while(m--) { int opt=read(); if(opt==1) { int l=read(),r=read(); ll k=read(); change(1,1,n,l,r,k); } else { int l=read(),r=read(); write(query(1,1,n,l,r)); printf("\n"); } } return 0; }