線段樹是一種二叉樹,也就是對於乙個線段,我們會用乙個二叉樹來表示。
可以進行一些區間的修改和查詢。
線段樹通用的build方法
void build(int k,int l,int r)
int mid=(l+r)>>1;
build(ls(k),l,mid);
build(rs(k),mid+1,r);
pushup(k);//代表更新sum,這裡可以是sum[k]=sum[(ls(k)]+sum[rs(k)]。
}
因為要進行區間的查詢和修改,線段樹還需要兩個函式,check和update。check函式和update都用到了分治的思想。
簡單的應用是區間修改+單點查詢,區間查詢+單點修改。
區間修改單點查詢的思路是將區間標記,然後查詢時從上到下加起來,直到葉子節點。區間查詢+單點修改的思路是修改時直到葉子節點。單點的操作遞迴不會出現左右都有的情況,其餘與區間操作類似。
下面的**都是都是對區間進行操作的。
int check(int k,int l,int r,int x,int y)
void add(int k,int l,int r,int x,int y,int v)
int mid=(l+r)>>1;
if(x<=mid)add(ls(k),l,mid,x,y,v);
if(y>mid)add(rs(k),mid+1,r,x,y,v);
pushup(k);
}
線段樹可以進行複雜的區間修改和區間查詢操作,主要要用到pushdown函式和懶標記。
懶標記是修改的因子,在對某個節點進行操作時,如果不需要對其兒子節點進行操作,就盡在這個節點進行懶標記,如果後邊會對兒子節點進行修改查詢操作,就要pushdown,向下傳遞懶標記。還有一些特殊的根號線段樹和除法線段樹。
題意題目要求維護區間並求區間的方差,通過化簡可以得知,求解方差只需要維護區間平方和與區間和即可。
**
int const maxn=1000005;
double sum1[maxn*2],sum2[maxn*2],tree[maxn],lazy[maxn*2];
inline int read()
while(c>='0'&&c<='9')
return x*f;
}void pushup(int k)
void build(int k,int l,int r)
int mid=(l+r)>>1;
build(ls(k),l,mid);
build(rs(k),mid+1,r);
pushup(k);
}void pushdown(int k,int l,int r)//pushdown的寫法一般是線段樹題目的核心
double check1(int k,int l,int r,int x,int y)
double check2(int k,int l,int r,int x,int y)
void add(int k,int l,int r,int x,int y,double v)
if(lazy[k])pushdown(k,l,r);//關鍵**
int mid=(l+r)>>1;
if(x<=mid)add(ls(k),l,mid,x,y,v);
if(y>mid)add(rs(k),mid+1,r,x,y,v);
pushup(k);
}main(void)
build(1,1,n);
for(int i=1;i<=m;i++)
if(cmd==2)
if(cmd==3)
}}
題意
簡單的區間維護
**
const int maxn=100005;
int sum[maxn*4],a[maxn],lazy[maxn*4];
void build(int k,int l,int r)
int mid=(r+l)>>1;
build(ls(k),l,mid);
build(rs(k),mid+1,r);
sum[k]=sum[ls(k)]+sum[rs(k)];
}void pushdown(int k,int l,int r)
void add(int k,int l,int r,int x,int y,int z)
if(lazy[k])pushdown(k,l,r);
int mid=(l+r)>>1;
if(x<=mid)add(ls(k),l,mid,x,y,z);
if(y>mid)add(rs(k),mid+1,r,x,y,z);
//得到子樹後加到父親節點
sum[k]=sum[ls(k)]+sum[rs(k)];
}int check(int k,int l,int r,int x,int y)
main(void)
else
} }
題意
維護區間的乘積和加法,兩個懶標記,乙個為乘積因子,乙個為加法因子
**
const int maxn=200010;
int p,a[maxn],sum[4*maxn],mul[4*maxn],add[4*maxn];
inline void qm1(int k)
inline void build(int k,int l,int r)
int mid=(l+r)/2;
build(ls(k),l,mid);
build(rs(k),mid+1,r);
sum[k]=sum[ls(k)]+sum[rs(k)];
}inline void pushdown(int k,int l,int r)
inline void add(int k,int l,int r,int x,int y,int v)
pushdown(k,l,r);
int mid=(l+r)/2;
if(x<=mid)add(ls(k),l,mid,x,y,v);
if(y>mid)add(rs(k),mid+1,r,x,y,v);
sum[k]=sum[ls(k)]+sum[rs(k)];
}inline void mul(int k,int l,int r,int x,int y,int v)
pushdown(k,l,r);
int mid=(l+r)/2;
if(x<=mid)mul(ls(k),l,mid,x,y,v);
if(y>mid)mul(rs(k),mid+1,r,x,y,v);
sum[k]=sum[ls(k)]+sum[rs(k)];
}inline int check(int k,int l,int r,int x,int y)
main(void)
build(1,1,n);
_1for(j,m)
if(cmd==2)
if(cmd==3)
}}
Web前端 從入門到自閉
標籤的快捷鍵 單詞 tab鍵 單詞 h5初始 tab 快速建立符合規範的html doctype html html lang en head meta charset utf 8 title document title head body body html html的注釋 css的注釋 注釋的...
線段樹入門
線段樹 interval tree 是把區間逐次二分得到的一樹狀結構,它反映了包括歸併排序在內的很多分治演算法的問題求解方式。上圖是一棵典型的線段樹,它對區間 1,10 進行分割,直到單個點。這棵樹的特點 是 1.每一層都是區間 a,b 的乙個劃分,記 l b a 2.一共有log2l層 3.給定乙...
線段樹入門
學習下 線段樹的入門級 總結 線段樹是一種二叉搜尋樹,與區間樹相似,它將乙個區間劃分成一些單元區間,每個單元區間對應線段樹中的乙個葉結點。對於線段樹中的每乙個非葉子節點 a,b 它的左兒子表示的區間為 a,a b 2 右兒子表示的區間為 a b 2 1,b 因此線段樹是平衡二叉樹,最後的子節點數目為...