【数据结构】线段树总结(一)
2016-08-13 11:00
441 查看
线段树在求区间某些值,如区间求和,区间最值等具有明显优势,能将原本朴素的求法O(n)的复杂度减小到 log(n)
这是线段树在求区间最大值的一个应用
###HDU 1166 - 敌兵布阵
Online Judge : http://acm.hdu.edu.cn/showproblem.php?pid=1166
这有对区间求和,也有对某个长度为1的特定区间的数值更新。代码与上面提到的例子(HDU 1754)有异曲同工之妙,将代码稍作更改即可。
###POJ 3468 - A Simple Problem with Integers
这题出现了对长度大于1的区间进行数值更新的情况,比上两个例子较为复杂,主要是在对数值的更新问题上。
HDU 1754 - I Hate It
Online judge : http://acm.hdu.edu.cn/showproblem.php?pid=1754这是线段树在求区间最大值的一个应用
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int MAXN = 200010; struct seg { int l;//表示该区间下标的最小值 int r;//表示该区间下标的最大值 int n;//区间的某个数值,这里指最大值 }T[4*MAXN]; void build(int l,int r,int id) { T[id].l=l; T[id].r=r; T[id].n=0; if(l == r) { return; } int mid = (l+r)/2; build(l,mid,2*id);//递归求左儿子相关信息 build(mid+1,r,2*id+1);//递归求右儿子相关消息 } //更新区间值。三个参数分别指要更新的数值、更新数值所在的区间、使用的线段树数组下标 void update(int val,int des,int id) { if(T[id].l==T[id].r && T[id].l==des) { T[id].n=val; return; } int mid=(T[id].l+T[id].r)/2; if(des <= mid) update(val,des,2*id); else update(val,des,2*id+1); T[id].n=max(T[2*id].n,T[2*id+1].n); } int ans; //查询区间值。三个参数分别为区间下标的最小值、区间下标的最大值、使用的线段树数组下标 void query(int l,int r,int id) { if(T[id].l == l && T[id].r == r) { ans = max(T[id].n,ans); return; } int mid = (T[id].l + T[id].r)/2; if(r <= mid) query(l,r,2*id); else if(l>mid) query(l,r,2*id+1); else { query(l,mid,2*id); query(mid+1,r,2*id+1); } } int main() { int n,m; while(scanf("%d%d",&n,&m) != EOF) { build(1,n,1); //建立线段树。可以在建立线段树的时候将相关信息存入 for(int i=1;i<=n;i++) { int tmp; scanf("%d",&tmp); update(tmp,i,1); } for(int i=1;i<=m;i++) { char option[10]; int a,b; scanf("%s%d%d",&option,&a,&b); if(option[0] == 'Q') { ans = 0; query(a,b,1); cout<<ans<<endl; } else if(option[0] == 'U') { update(b,a,1); } } } return 0; }
###HDU 1166 - 敌兵布阵
Online Judge : http://acm.hdu.edu.cn/showproblem.php?pid=1166
这有对区间求和,也有对某个长度为1的特定区间的数值更新。代码与上面提到的例子(HDU 1754)有异曲同工之妙,将代码稍作更改即可。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int MAXN = 51000; struct seg { int l; int r; int n; }T[3*MAXN]; void build(int l,int r,int id) { if(l == r) { T[id].l=l; T[id].r=r; T[id].n=0; return; } int mid = (l+r)/2; T[id].l=l; T[id].r=r; T[id].n=0; build(l,mid,2*id); build(mid+1,r,2*id+1); } void update(int val,int des,int id) { if(T[id].l==T[id].r && T[id].l==des) { T[id].n+=val; return; } int mid=(T[id].l+T[id].r)>>1; if(des <= mid) update(val,des,2*id); else update(val,des,2*id+1); T[id].n=T[2*id].n+T[2*id+1].n; } int ans; void query(int l,int r,int id) { if(T[id].l == l && T[id].r == r) { ans += T[id].n; return; } int mid = (T[id].l + T[id].r)>>1; if(r <= mid) query(l,r,2*id); else if(l>mid) query(l,r,2*id+1); else { query(l,mid,2*id); query(mid+1,r,2*id+1); } } int main() { int t; scanf("%d",&t); for(int cas = 1;cas<=t;cas++) { int n; scanf("%d",&n); build(1,n,1); for(int i=1;i<=n;i++) { int tmp; scanf("%d",&tmp); update(tmp,i,1); } printf("Case %d:\n",cas); char str[20]; while(scanf("%s",str)) { if(strcmp(str,"End")==0) break; int a,b; scanf("%d%d",&a,&b); if(strcmp(str,"Add")==0) update(b,a,1); else if(strcmp(str,"Sub")==0) update(-b,a,1); else if(strcmp(str,"Query")==0) { ans = 0; query(a,b,1); cout<<ans<<endl; } } } return 0; }
###POJ 3468 - A Simple Problem with Integers
这题出现了对长度大于1的区间进行数值更新的情况,比上两个例子较为复杂,主要是在对数值的更新问题上。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int MAXN = 100100; long long sum[4*MAXN]; long long addv[4*MAXN]; //用结构体将区间左值、右值、和、要加的数同时表示亦可,使用起来略复杂 void Pushdown(int id,int diff) { if(addv[id]) { sum[2*id] += addv[id]*(diff-diff/2); //左儿子的数值 加上 要加的数值乘以左儿子区间长度 sum[2*id+1] += addv[id]*(diff/2); //右儿子的数值 加上 要加的数值乘以右儿子区间长度 addv[2*id] += addv[id]; //更新左儿子所在区间应加的数值 addv[2*id+1] += addv[id]; //更新右儿子所在区间应加的数值 addv[id]=0; } } void pushup(int id) { sum[id]=sum[2*id]+sum[2*id+1]; //将左儿子的数值与右儿子的数值相加更新父节点的数值 } void build(int l,int r,int id) { addv[id]=0; if(l == r) { scanf("%I64d",&sum[id]); //在树初始化的时候更新树叶值 比 初始化后在插入更新树叶值 复杂度相同 return; } int mid = (l+r)/2; build(l,mid,2*id); build(mid+1,r,2*id+1); Pushup(id); } void update(int ql,int qr,int val,int l,int r,int id) { if(ql <= l && qr >= r) { addv[id]+=val; sum[id]+=(long long)val*(r-l+1); //增加的数值乘以区间长度 return; } Pushdown(id,r-l+1); int mid = (l+r)/2; if(ql <= mid) update(ql,qr,val,l,mid,2*id); if(qr > mid) update(ql,qr,val,mid+1,r,2*id+1); Pushup(id); } long long query(int ql,int qr,int l,int r,int id) { if(ql <= l && qr >= r) return sum[id]; Pushdown(id,r-l+1); long long res = 0; int mid = (l+r)/2; if(qr > mid) res += query(ql,qr,mid+1,r,2*id+1); if(ql <= mid) res += query(ql,qr,l,mid,2*id); return res; } int main() { int n,q; while(scanf("%d%d",&n,&q) != EOF && n && q) { build(1,n,1); while(q--) { char option[10]; scanf("%s",&option); if(option[0] == 'Q') { int a,b; scanf("%d%d",&a,&b); ans = query(a,b,1,n,1); cout<<ans<<endl; } else if(option[0] == 'C') { int a,b,c; scanf("%d%d%d",&a,&b,&c); update(a,b,c,1,n,1); } } } return 0; }
相关文章推荐
- 数据结构总结之线段树
- 数据结构总结之线段树
- 数据结构总结(一):一种特殊的有序队列
- 数据结构总结
- Java数据结构应用——无序列表学习总结(一)
- 2010暑期集训第一专题(数据结构)总结
- 精英计划第五周数据结构试验总结-飞鹰组
- 数据结构学习总结
- Java数据结构应用——无序列表学习总结(二)
- C# 数据结构常用术语总结
- 数据结构和算法面试总结
- 网络编程数据结构 及函数总结
- 问题一,要想进外企,英语当然要硬,其他的要看你对数据结构的理解,先总结一下。
- 数据结构总结(摘抄)(一)
- 数据结构,查找方法总结
- 问题二,要想进外企,英语当然要硬,其他的要看你对数据结构的理解,先总结一下。类与结构的区别
- <数据结构>(严版)第1~4章学习总结
- 数据结构总结
- 关于本菜对线段树的总结
- 数据结构简单要点总结(转)