【线段树】
本质是二叉树,每个节点表示一个区间 [ L, R ],设 m = (R - L + 1) / 2 (该处结果向下取整) 左孩子区间为 [ L, m ] , 右孩子区间为 [ m+1 , R ]
同时每个节点(即每个区间)维护一个信息 (该信息能通过子节点区间结果合并得到父区间结果)
图解:
例如对于数组[2, 5, 1, 4, 9, 3]可以构造如下的二叉树(背景为白色表示叶子节点,非叶子节点的值是其对应数组区间内的最小值,例如根节点表示数组区间arr[0...5]内的最小值是1):
区间信息:该区间上的最小值
【应用】
动态RMQ
【模板】
点修改模板参见例题hdu1754
区间修改模板(此处有个优化:延迟标记)
【例题】
hdu1754
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
/* hdu1754 找区间最大值 */ #include<iostream> #include<cstdio> #include<algorithm> using namespace std; const int INF = -100; const int maxn = 2000100; int segtree[maxn]; inline void pushup(int root){ segtree[root] = max( segtree[root*2], segtree[root*2+1] ); } void built(int root, int L, int R){ if(L==R){ scanf("%d", &segtree[root]); return; } int m = (R+L)/2; built(root*2, L, m); built(root*2+1, m+1, R); pushup(root); } //cL current L cR current right int query(int root, int cL, int cR, int qL, int qR){ if(qL<=cL && cR<=qR) return segtree[root]; //查询区间完全包含当前区间 int ans = INF; int m = (cR+cL)/2; if(qL<=m) ans = max( ans, query(root*2, cL, m, qL, qR) ); //如果查询的区间有部分在当前节点的左子树 if(m<qR) ans = max( ans, query(root*2+1, m+1, cR, qL, qR) );//如果查询的区间有部分在当前节点的右子树 return ans; } //修改第p个元素为v void update(int root, int cL, int cR, int p, int v){ if(cL == cR){ segtree[root] = v; return; } int m = (cR+cL)/2; if(p<=m) update(root*2, cL, m, p, v); else update(root*2+1, m+1, cR, p, v); pushup(root); } int main(){ int n, m; char oder; int qL, qR; int p, v; while(scanf("%d%d", &n, &m)==2){ built(1, 1, n); // // for(int i=1;i<=9;++i) cout << segtree[i] << " "; // cout << endl; // while(m--){ getchar(); scanf("%c", &oder); if(oder=='Q'){ scanf("%d%d", &qL, &qR); // // cout << "qL=" << qL << " qR="<< qR << endl; ///// printf("%d\n", query(1, 1, n, qL, qR)); } else{ scanf("%d%d", &p, &v); update(1, 1, n, p, v); } } } return 0; }
hdu 1166 求区间和
hdu 1698 成段更新
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
//hdu 1698 成段更新 //基础的线段树模板题 #include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; typedef long long ll; const int maxn=100005; int t,n,q; ll sum[maxn*4],add[maxn*4]; void pushup(int rt){ sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } void pushdown(int rt,int len){ if(add[rt]){ add[rt<<1]=add[rt]; add[rt<<1|1]=add[rt]; sum[rt<<1]=add[rt]*(len-(len>>1)); sum[rt<<1|1]=add[rt]*(len>>1); add[rt]=0; } } void build(int l,int r,int rt){ add[rt]=0; if(l==r){ //scanf("%I64d",&sum[rt]); sum[rt]=1; return; } int m=(l+r)>>1; build(l,m,rt<<1); build(m+1,r,rt<<1|1); pushup(rt); } void update(int L,int R,int c,int l,int r,int rt){ if(L<=l&&R>=r){ add[rt]=c; sum[rt]=(ll)c*(r-l+1); return; } pushdown(rt,r-l+1); int m=(l+r)>>1; if(L<=m) update(L,R,c,l,m,rt<<1); if(R>m) update(L,R,c,m+1,r,rt<<1|1); pushup(rt); } ll querry(int L,int R,int l,int r,int rt){ if(L<=l&&R>=r) return sum[rt]; pushdown(rt,r-l+1); int m=(l+r)>>1; ll ans=0; if(L<=m) ans+=querry(L,R,l,m,rt<<1); if(R>m) ans+=querry(L,R,m+1,r,rt<<1|1); return ans; } int main() { int x,y,z; scanf("%d",&t); for(int cas=1;cas<=t;cas++){ scanf("%d%d",&n,&q); build(1,n,1); while(q--){ scanf("%d%d%d",&x,&y,&z); update(x,y,z,1,n,1); } printf("Case %d: The total value of the hook is %I64d.\n",cas,querry(1,n,1,n,1)); } }
更多:http://blog.csdn.net/zxy_snow/article/details/6952046
【参考】
白书P199
http://www.cnblogs.com/TenosDoIt/p/3453089.html
http://blog.csdn.net/zip_fan/article/details/46775633