线段树代码整理
来源:互联网 发布:何方抢票软件 编辑:程序博客网 时间:2024/06/03 16:32
· 单点更新:最最基础的线段树,只更新叶子节点,然后把信息用PushUP(int r)这个函数更新上来
o hdu1166敌兵布阵
题意:O(-1)
思路:O(-1)
线段树功能:update:单点增减 query:区间求和
/*************************************************************************> File Name: hdu1166.cpp> Author: FangPin> Mail: fangpin1993@hotmail.com> Created Time: 六 3/ 5 22:07:17 2016 ************************************************************************/#include<iostream>using namespace std;class SegmentTree{private: int *a; void pushup(int rt){ a[rt]=a[rt<<1]+a[rt<<1|1]; }public: SegmentTree(int n){ a=new int[n<<2]; } ~SegmentTree(){ delete[] a; } void build(int rt,int l,int r){ if(l==r){ scanf("%d",&a[rt]); return ; } else{ int m=(l+r)>>1; build(rt<<1,l,m); build(rt<<1|1,m+1,r); pushup(rt); } } void update(int rt,int l,int r,int pos,int val){ if(l==r){ a[rt]+=val; return; } int m=(l+r)>>1; if(m>=pos) update(rt<<1,l,m,pos,val); else update(rt<<1|1,m+1,r,pos,val); pushup(rt); } int query(int rt,int l,int r,int x,int y){ if(x<=l && y>=r) return a[rt]; int ans=0; int m=(l+r)>>1; if(x<=m) ans+=query(rt<<1,l,m,x,y); if(y>m) ans+=query(rt<<1|1,m+1,r,x,y); return ans; }};int main(){ int t; scanf("%d",&t); for(int ca=0;ca<t;++ca){ int n; scanf("%d",&n); SegmentTree sum(n); sum.build(1,1,n); printf("Case %d:\n",ca+1); char s[10]; while(scanf("%s",s),s[0]!='E'){ if(s[0]=='Q'){ int x,y; scanf("%d%d",&x,&y); printf("%d\n",sum.query(1,1,n,x,y)); } else{ int pos,val; scanf("%d%d",&pos,&val); if(s[0]=='S') val=-val; sum.update(1,1,n,pos,val); } } }}
o hdu1754 I Hate It
题意:O(-1)
思路:O(-1)
线段树功能:update:单点替换 query:区间最值
/*************************************************************************> File Name: hdu1754.cpp> Author: FangPin> Mail: fangpin1993@hotmail.com> Created Time: 日 3/ 6 21:24:47 2016 ************************************************************************/#include<iostream>#include <algorithm>#include <cstdio>using namespace std;class SegmentTree{private: int *a; void pushup(int rt){ a[rt]=max(a[rt<<1],a[rt<<1|1]); }public: SegmentTree(int n){ a=new int[n<<2]; } ~SegmentTree(){ delete[] a; } void build(int rt,int l,int r){ if(l==r){ scanf("%d",a+rt); return; } int m=(l+r)>>1; build(rt<<1,l,m); build(rt<<1|1,m+1,r); pushup(rt); } void update(int rt,int l,int r,int pos,int val){ if(l==r){ a[rt]=val; return ; } int m=(l+r)>>1; if(m>=pos) update(rt<<1,l,m,pos,val); else update(rt<<1|1,m+1,r,pos,val); pushup(rt); } int query(int rt,int l,int r,int x,int y){ if(x<=l && y>=r) return a[rt]; int m=(l+r)>>1; int ans=-(1<<30); if(x<=m) ans=max(ans,query(rt<<1,l,m,x,y)); if(y>m) ans=max(ans,query(rt<<1|1,m+1,r,x,y)); return ans; }};int main(){ int n,m; while(scanf("%d%d",&n,&m)==2){ SegmentTree st(n); st.build(1,1,n); char s[3]; int a,b; for(int i=0;i<m;++i){ scanf("%s%d%d",s,&a,&b); if(s[0]=='Q') printf("%d\n",st.query(1,1,n,a,b)); else st.update(1,1,n,a,b); } } return 0;}
o hdu1394 Minimum Inversion Number
题意:求Inversion后的最小逆序数
思路:用O(nlogn)复杂度求出最初逆序数后,就可以用O(1)的复杂度分别递推出其他解
线段树功能:update:单点增减 query:区间求和
/*************************************************************************> File Name: hdu1394.cpp> Author: FangPin> Mail: fangpin1993@hotmail.com> Created Time: 日 3/ 6 21:58:42 2016 ************************************************************************/#include<iostream>#include <algorithm>#include <cstdio>#include <cstring>using namespace std;class SegmentTree{private: int *a; void pushup(int rt){ a[rt]=a[rt<<1]+a[rt<<1|1]; }public: SegmentTree(int n){ a=new int[n<<2]; memset(a,0,(n<<2)*sizeof(int)); } ~SegmentTree(){ delete[] a; } void update(int rt,int l,int r,int pos){ if(l==r){ ++a[rt]; return; } int m=(l+r)>>1; if(m>=pos) update(rt<<1,l,m,pos); else update(rt<<1|1,m+1,r,pos); pushup(rt); } int query(int rt,int l,int r,int x,int y){ if(x<=l && y>=r) return a[rt]; int m=(l+r)>>1; int ans=0; if(m>=x) ans+=query(rt<<1,l,m,x,y); if(y>m) ans+=query(rt<<1|1,m+1,r,x,y); return ans; }};int data[5002];int main(){ int n; while(~scanf("%d",&n)){ SegmentTree st(n); int ret=0; for(int i=1;i<=n;++i){ scanf("%d",data+i); ++data[i]; st.update(1,1,n,data[i]); ret+=st.query(1,1,n,data[i]+1,n); } int ans=ret; for(int i=1;i<n;++i){ ret+=n+1-2*data[i]; ans=min(ans,ret); } printf("%d\n",ans); }}
o hdu2795 Billboard
题意:h*w的木板,放进一些1*L的物品,求每次放空间能容纳且最上边的位子
思路:每次找到最大值的位子,然后减去L
线段树功能:query:区间求最大值的位子(直接把update的操作在query里做了)
/*************************************************************************> File Name: hdu2795.cpp> Author: FangPin> Mail: fangpin1993@hotmail.com> Created Time: 一 3/ 7 22:09:59 2016 ************************************************************************/#include <cstdio>#include<iostream>#include <algorithm>using namespace std;class SegmentTree{private: int *a; void pushup(int rt){ a[rt]=max(a[rt<<1],a[rt<<1|1]); }public: SegmentTree(int n,int w){ a=new int[n<<2]; for(int i=1;i<(n<<2);++i) a[i]=w; } ~SegmentTree(){ delete[] a; } int query(int rt,int l,int r,int w){ if(l==r){ a[rt]-=w; return l; } int m=(l+r)>>1; int ans=(a[rt<<1]>=w)?query(rt<<1,l,m,w):query(rt<<1|1,m+1,r,w); pushup(rt); return ans; } int all_max()const{ return a[1]; }};int main(){ int h,w,n; while(scanf("%d%d%d",&h,&w,&n)==3){ SegmentTree st(min(h,n),w); for(int i=0;i<n;++i){ int x; scanf("%d",&x); if(st.all_max()<x) puts("-1"); else printf("%d\n",st.query(1,1,min(h,n),x)); } } return 0;}
poj 2828
</pre><pre code_snippet_id="1598774" snippet_file_name="blog_20160307_4_4006020" name="code" class="cpp">
/*************************************************************************> File Name: poj2828.cpp> Author: Fang Pin> Mail: fangpin1993@hotmail.com> Created Time: 2016年03月09日 星期三 22时01分29秒 ************************************************************************/#include<iostream>#include <algorithm>#include <cstring>#include <cstdio>using namespace std;class SegmentTree{private: int *a,*b; void pushup(int rt){ a[rt]=a[rt<<1]+a[rt<<1|1]; }public: SegmentTree(int n){ a=new int[n<<2]; b=new int[n]; } ~SegmentTree(){ delete[] a; } void build(int rt,int l,int r){ if(l==r){ a[rt]=1; return ; } int m=(l+r)>>1; build(rt<<1,l,m); build(rt<<1|1,m+1,r); pushup(rt); } void update(int rt,int l,int r,int pos,int val){ if(l==r){ a[rt]=0; b[l]=val; return; } int m=(l+r)>>1; if(a[rt<<1]>=pos) update(rt<<1,l,m,pos,val); else update(rt<<1|1,m+1,r,pos-a[rt<<1],val); pushup(rt); } int getans(int pos)const{ return b[pos]; }};int b[200002],data[200002][2];int main(){ int t; while(~scanf("%d",&t)){ SegmentTree st(t); st.build(1,1,t); for(int i=1;i<=t;++i) scanf("%d%d",&data[i][0],&data[i][1]); for(int i=t;i>0;--i) st.update(1,1,t,data[i][0]+1,data[i][1]); for(int i=1;i<t;++i) printf("%d ",st.getans(i)); printf("%d\n",st.getans(t)); } return 0;}
· 成段更新(通常这对初学者来说是一道坎),需要用到延迟标记(或者说懒惰标记),简单来说就是每次更新的时候不要更新到底,用延迟标记使得更新延迟到下次需要更新or询问到的时候
o hdu1698 Just a Hook
题意:O(-1)
思路:O(-1)
线段树功能:update:成段替换 (由于只query一次总区间,所以可以直接输出1结点的信息)
/*************************************************************************> File Name: hdu1698.cpp> Author: Fang Pin> Mail: fangpin1993@hotmail.com> Created Time: 2016年03月11日 星期五 22时06分04秒 ************************************************************************/#include<iostream>#include <cstdio>#include <algorithm>using namespace std;class SegmentTree{private: int *a; int *lazy; void pushup(int rt){ a[rt]=a[rt<<1]+a[rt<<1|1]; } void pushdown(int rt,int len){ if(lazy[rt]){ lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt]; a[rt<<1]=(len-(len>>1))*lazy[rt]; a[rt<<1|1]=(len>>1)*lazy[rt]; lazy[rt]=0; } }public: SegmentTree(int n){ a=new int[n<<2]; lazy=new int[n<<2]; fill(lazy,lazy+(n<<2),0); } ~SegmentTree(){ delete []a; delete []lazy; } void build(int rt,int l,int r){ if(l==r){ a[rt]=1; return ; } int m=(l+r)>>1; build(rt<<1,l,m); build(rt<<1|1,m+1,r); pushup(rt); } void update(int rt,int l,int r,int x,int y,int val){ if(x<=l && y>=r){ lazy[rt]=val; a[rt]=(r-l+1)*val; return; } pushdown(rt,r-l+1); int m=(l+r)>>1; if(x<=m) update(rt<<1,l,m,x,y,val); if(y>m) update(rt<<1|1,m+1,r,x,y,val); pushup(rt); } int ans()const{ return a[1]; }};int main(){ int t; scanf("%d",&t); for(int ca=1;ca<=t;++ca){ int n,m; scanf("%d%d",&n,&m); SegmentTree st(n); st.build(1,1,n); for(int i=0;i<m;++i){ int a,b,c; scanf("%d%d%d",&a,&b,&c); st.update(1,1,n,a,b,c); } printf("Case %d: The total value of the hook is %d.\n",ca,st.ans()); } return 0;}
o poj3468 A Simple Problem with Integers
题意:O(-1)
思路:O(-1)
线段树功能:update:成段增减 query:区间求和
/*************************************************************************> File Name: poj3468.cpp> Author: Fang Pin> Mail: fangpin1993@hotmail.com> Created Time: 日 3/13 23:16:31 2016 ************************************************************************/#include<iostream>#include <cstdio>#include <cstring>using namespace std;class SegmentTree{private: long long *a,*lazy; void pushup(int rt){ a[rt]=a[rt<<1]+a[rt<<1|1]; } void pushdown(int rt,int len){ if(lazy[rt]){ lazy[rt<<1]+=lazy[rt]; lazy[rt<<1|1]+=lazy[rt]; a[rt<<1]+=(len-(len>>1))*lazy[rt]; a[rt<<1|1]+=(len>>1)*lazy[rt]; lazy[rt]=0; } }public: SegmentTree(int n){ a=new long long[n<<2]; lazy=new long long[n<<2]; memset(lazy,0,(n<<2)*sizeof(long long)); } ~SegmentTree(){ delete[] a; delete[] lazy; } void build(int rt,int l,int r){ if(l==r){ scanf("%lld",&a[rt]); return ; } int m=(l+r)>>1; build(rt<<1,l,m); build(rt<<1|1,m+1,r); pushup(rt); } void update(int rt,int l,int r,int x,int y,long long val){ if(x<=l && y>=r){ lazy[rt]+=val; a[rt]+=(r-l+1)*val; return; } int m=(l+r)>>1; pushdown( rt, r-l+1); if(x<=m) update(rt<<1,l,m,x,y,val); if(y>m) update(rt<<1|1,m+1,r,x,y,val); pushup(rt); } long long query(int rt,int l,int r,int x,int y){ if(x<=l && y>=r) return a[rt]; pushdown(rt,r-l+1); int m=(l+r)>>1; long long ans=0; if(x<=m) ans+=query(rt<<1,l,m,x,y); if(y>m) ans+=query(rt<<1|1,m+1,r,x,y); return ans; }};int main(){ int n,m; scanf("%d%d",&n,&m); SegmentTree st(n); st.build(1,1,n); while(m--){ char s[3]; scanf("%s",s); if(s[0]=='Q'){ int a,b; scanf("%d%d",&a,&b); printf("%lld\n",st.query(1,1,n,a,b)); } else{ int a,b,c; scanf("%d%d%d",&a,&b,&c); st.update(1,1,n,a,b,c); } } return 0;}
poj1436Horizontally Visible Segments
- 对y轴进行建树,对每条线段按横轴从小到大排序,从第1条线段开始查询并更新
- 查询该条线段所表示的区间内不同颜色数量(即可见线段数)并且记录可见线段,然后更新该区间颜色
- 最后暴力求两两可见线段数量
- 但是注意:0,4,1 和 0,2,2 和 3,4,2这三条线段覆盖的结果是区间0~4通过线段树查找可见线段是两条,其实是3条(2~3可见另一条)
- 可以把查询更新的区间*2,比如上面数据变成0,8,1 和 0,4,2 和 6,8,2则4~6之间可见一条线段
/*************************************************************************> File Name: 1436.cpp> Author: Fang Pin> Mail: fangpin1993@hotmail.com> Created Time: 五 3/18 21:57:58 2016 ************************************************************************/#include<iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <set>using namespace std;const int MAXN=8005;struct Node{ int y1,y2,x;}data[MAXN];//bool hash[MAXN];int lazy[MAXN<<3];bool lk[MAXN][MAXN];void build(){ memset(lazy,0,sizeof(lazy));}void pushdown(int rt){ if(lazy[rt]){ lazy[rt<<1]=lazy[rt]; lazy[rt<<1|1]=lazy[rt]; lazy[rt]=0; }}void update(int rt,int l,int r,int x,int y,int val){ if(x<=l && y>=r){ lazy[rt]=val; return ; } int m=(l+r)>>1; pushdown(rt); if(x<=m) update(rt<<1,l,m,x,y,val); if(y>m) update(rt<<1|1,m+1,r,x,y,val);}void query(int rt,int l,int r,int x,int y,int pos){ if(lazy[rt]){ lk[lazy[rt]][pos]=true; return; } if(l==r) return ; int m=(l+r)>>1; pushdown(rt); if(x<=m) query(rt<<1,l,m,x,y,pos); if(y>m) query(rt<<1|1,m+1,r,x,y,pos);}void init(){ memset(lk,false,sizeof(lk));}bool cmp(const Node &a,const Node &b){ return a.x<b.x;}int main(){ int t,n; scanf("%d",&t); while(t--){ init(); int n; scanf("%d",&n); for(int i=0;i<n;++i){ scanf("%d%d%d",&data[i].y1,&data[i].y2,&data[i].x); if(data[i].y1>data[i].y2) swap(data[i].y1,data[i].y2); data[i].y1*=2; data[i].y2*=2; } sort(data,data+n,cmp); build(); for(int i=0;i<n;++i){ query(1,1,MAXN<<1,data[i].y1,data[i].y2,i+1); update(1,1,MAXN<<1,data[i].y1,data[i].y2,i+1); } int ans=0; //. debug(n); for(int i=1;i<=n;++i){ for(int j=i+1;j<=n;++j){ if(lk[i][j]) for(int k=j+1;k<=n;++k){ if(lk[i][k] && lk[j][k]) ++ans; } } } printf("%d\n",ans); }}
· 区间合并
这类题目会询问区间中满足条件的连续最长区间,所以PushUp的时候需要对左右儿子的区间进行合并
o poj3667 Hotel
题意:1 a:询问是不是有连续长度为a的空房间,有的话住进最左边
2 a b:将[a,a+b-1]的房间清空
思路:记录区间中最长的空房间
线段树操作:update:区间替换 query:询问满足条件的最左断点
/*************************************************************************> File Name: poj3667.cpp> Author: Fang Pin> Mail: fangpin1993@hotmail.com> Created Time: 四 3/24 22:20:43 2016************************************************************************/#include<iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int MAXN=55555;int sum[MAXN<<2],lsum[MAXN<<2],rsum[MAXN<<2],lazy[MAXN<<2];void pushup(int rt,int len){ lsum[rt]=(lsum[rt<<1]==len-(len>>1))?lsum[rt<<1]+lsum[rt<<1|1]:lsum[rt<<1]; rsum[rt]=(rsum[rt<<1|1]==(len>>1))?rsum[rt<<1|1]+rsum[rt<<1]:rsum[rt<<1|1]; sum[rt]=max(max(sum[rt<<1],sum[rt<<1|1]),rsum[rt<<1]+lsum[rt<<1|1]);}void build(int rt,int l,int r){ sum[rt]=lsum[rt]=rsum[rt]=r-l+1; lazy[rt]=-1; if(l==r) return; int m=(l+r)>>1; build(rt<<1,l,m); build(rt<<1|1,m+1,r);}void pushdown(int rt,int m){ if (lazy[rt] != -1) {lazy[rt<<1] = lazy[rt<<1|1] = lazy[rt];sum[rt<<1] = lsum[rt<<1] = rsum[rt<<1] = lazy[rt] ? 0 : m - (m >> 1);sum[rt<<1|1] = lsum[rt<<1|1] = rsum[rt<<1|1] = lazy[rt] ? 0 : (m >> 1);lazy[rt] = -1;}}int query(int rt,int l,int r,int x){ if(l==r) return l; pushdown(rt,r-l+1); int m=(l+r)>>1; if(sum[rt<<1]>=x) return query(rt<<1,l,m,x); else if(rsum[rt<<1]+lsum[rt<<1|1]>=x) return m-rsum[rt<<1]+1; else return query(rt<<1|1,m+1,r,x);}void update(int rt,int l,int r,int x,int y,int val){ if(x<=l && y>=r){ lazy[rt]=val; sum[rt]=lsum[rt]=rsum[rt]=val?0:r-l+1; return; } pushdown(rt,r-l+1); int m=(r+l)>>1; if(x<=m) update(rt<<1,l,m,x,y,val); if(y>m) update(rt<<1|1,m+1,r,x,y,val); pushup(rt,r-l+1);}int main(){ int n,m; while(~scanf("%d%d",&n,&m)){ build(1,1,n); for(int i=0;i<m;++i){ int op,x,y; scanf("%d",&op); if(op==1){ scanf("%d",&x); if(sum[1]<x) puts("0"); else{ int ans=query(1,1,n,x); printf("%d\n",ans); update(1,1,n,ans,ans+x-1,1); } } else{ scanf("%d%d",&x,&y); update(1,1,n,x,x+y-1,0); } } } return 0;}
HDU3308-LCIS-线段树区间合并
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308
题目大意:给n个数,两种操作
1:U a,b 更新第a个为b (从0开始)
2:Q a,b 查询 a,b之间LCIS(最长连续递增子序列)的长度。
其实也可以说是个模板题;三个变量保存数据ls,rs,ms分别保存从左端点开始的最长连续上升子序列,从右端点开始的最长连续上升子序列,以及这个区间的最长连续上升子序列;唯一不同的就是这里得判断一下是否能够合并;即增加一个比较如果num[mid]<num[mid+1](num数组保存的是输入的数据
/*************************************************************************> File Name: hdu3308.cpp> Author: Fang Pin> Mail: fangpin1993@hotmail.com> Created Time: 日 3/27 21:47:12 2016 ************************************************************************/#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int MAXN=100002;int data[MAXN];int a[MAXN<<2],la[MAXN<<2],ra[MAXN<<2];void pushup(int rt,int l,int r){ int m=(l+r)>>1; la[rt]=la[rt<<1]; if(la[rt]==m-l+1 && data[m]<data[m+1]) la[rt]+=la[rt<<1|1]; ra[rt]=ra[rt<<1|1]; if(ra[rt]==r-m && data[m]<data[m+1]) ra[rt]+=ra[rt<<1]; a[rt]=max(a[rt<<1],a[rt<<1|1]); if(data[m]<data[m+1]) a[rt]=max(a[rt],ra[rt<<1]+la[rt<<1|1]);}void build(int rt,int l,int r){ if(l==r){ a[rt]=la[rt]=ra[rt]=1; return; } int m=(l+r)>>1; build(rt<<1,l,m); build(rt<<1|1,m+1,r); pushup(rt,l,r);}void update(int rt,int l,int r,int pos){ if(l==r){ return ; } int m=(l+r)>>1; if(pos<=m) update(rt<<1,l,m,pos); else if(pos>m) update(rt<<1|1,m+1,r,pos); pushup(rt,l,r);}int query(int rt,int l,int r,int x,int y){ if(x<=l && y>=r){ return a[rt]; } int m=(l+r)>>1; int ans=0; if(x<=m) ans=max(ans,query(rt<<1,l,m,x,y)); if(y>m) ans=max(ans,query(rt<<1|1,m+1,r,x,y)); if(x<=m && y>m && data[m]<data[m+1]) ans=max(ans,min(m-x+1,ra[rt<<1])+min(y-m,la[rt<<1|1])); return ans;}int main(){ int t; scanf("%d",&t); while(t--){ int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;++i){ scanf("%d",&data[i]); } build(1,1,n); char s[10]; int x,y; for(int i=0;i<m;++i){ scanf("%s%d%d",s,&x,&y); if(s[0]=='Q'){ printf("%d\n",query(1,1,n,x+1,y+1)); } else{ data[x+1]=y; update(1,1,n,x+1); } } }}
- 线段树代码整理
- 线段树整理
- 线段树整理
- 线段树题型整理
- 线段树整理
- 线段树模板整理
- 线段树整理
- 线段树整理
- 线段树+树状数组整理
- 大牛整理的线段树集锦
- 线段树&树状数组学习整理
- 线段树的代码模板
- 线段树建树思路代码
- java代码实现线段树
- 几道线段树的代码
- 笔记--线段树,IDA*伪代码
- 线段树单点更新思路代码
- 线段树查询操作思路代码
- 第十四章编程练习(5)
- Android使用 LruCache 缓存图片
- Android面试可能会问到的问题
- POJ 1004
- 集合类学习之Hashmap机制研究
- 线段树代码整理
- 蓝桥杯-剪格子(搜索)
- HBase笔记(一)
- 【GDOI 模拟3.5】总结
- 关于毕业设计——面向运动的无线体域网系统设计的构想
- Yahoo性能优化35条军规
- 西南BANG 之 android学习笔记1——5个android UI 布局
- python2.5 编译出错
- UVA 12504(模拟)