首页 > 代码库 > ·专题」 线段树
·专题」 线段树
初学线段树(SegmentTree)
从HH大神那你学来的模板风格。
感觉确实相当飘逸。
现在做了4题。。单点更新的,
想放上来,,以后慢慢整理!!
·单点更新」 ·刷题参考」
- hdu1166 敌兵布阵
- 线段树第一题,单点更新第一题,可以作为线段树的模板,
- 思路:兵工厂作为数量n映射作为线段总长,更具输入进行单点的更新与查询,sub操作可以理解为add一个负数
- Query操作:区间求和 update操作:单点的增减
- View Code
1 #include<cstdio> 2 3 #define lson l, m, rt<<1 4 #define rson m + 1, r, rt<<1 | 1 5 #define mid(a,b) (a+b)>>1 6 #define maxn 55555 7 8 int sum[maxn<<2]; 9 10 void PushUP(int rt) 11 { 12 sum[rt] = sum[rt<<1] + sum[rt<<1|1]; 13 } 14 15 void Build(int l,int r,int rt) 16 { 17 if(l == r) 18 { 19 scanf("%d",&sum[rt]); 20 return; 21 } 22 int m = mid(l,r); 23 Build(lson); 24 Build(rson); 25 PushUP(rt); 26 } 27 28 void Update(int p,int add,int l,int r,int rt) 29 { 30 if(l == r) 31 { 32 sum[rt] += add; 33 return; 34 } 35 int m = mid(l,r); 36 if(p <= m) 37 Update(p,add,lson); 38 else 39 Update(p,add,rson); 40 41 PushUP(rt); 42 } 43 44 int Query(int L,int R,int l,int r,int rt) 45 { 46 if(L <= l && r<= R) 47 { 48 return sum[rt]; 49 } 50 int m = mid(l,r); 51 int ans = 0; 52 if(L <= m) 53 ans += Query(L,R,lson); 54 if(R > m) 55 ans += Query(L,R,rson); 56 57 return ans; 58 } 59 60 61 int main() 62 { 63 int T,n,a,b; 64 scanf("%d",&T); 65 for(int cas=1;cas<=T;cas++) 66 { 67 printf("Case %d:\n",cas); 68 scanf("%d",&n); 69 Build(1,n,1); 70 71 char op[10]; 72 73 while(scanf("%s",op) && op[0] != ‘E‘) 74 { 75 scanf("%d %d",&a,&b); 76 if(op[0] == ‘Q‘) 77 printf("%d\n",Query(a,b,1,n,1)); 78 else if(op[0] == ‘S‘) 79 Update(a,-b,1,n,1); 80 else 81 Update(a,b,1,n,1); 82 } 83 } 84 return 0; 85 }
- hdu1754 I Hate It
- Query操作:区间最值 update操作:单点替换
- View Code
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 #define lson l, m, rt<<1 5 #define rson m + 1, r, rt<<1 | 1 6 #define mid(l,r) (l+r)>>1 7 #define maxn 222222 8 9 int MAX[maxn<<2]; 10 11 void PushUP(int rt) 12 { 13 MAX[rt] = max(MAX[rt<<1],MAX[rt<<1|1]); 14 } 15 16 void Build(int l,int r,int rt) 17 { 18 if(l == r) 19 { 20 scanf("%d",&MAX[rt]); 21 return; 22 } 23 int m = mid(l,r); 24 Build(lson); 25 Build(rson); 26 PushUP(rt); 27 } 28 29 void Update(int p,int sc,int l,int r,int rt) 30 { 31 if(l == r) 32 { 33 MAX[rt] = sc; 34 return; 35 } 36 int m = mid(l,r); 37 if(p <= m) 38 Update(p,sc,lson); 39 else 40 Update(p,sc,rson); 41 PushUP(rt); 42 } 43 44 int Query(int L,int R,int l,int r,int rt) 45 { 46 if(L <= l && r <= R) 47 return MAX[rt]; 48 int m = mid(l,r); 49 int ans = 0; 50 if(L <= m) 51 ans = max(ans,Query(L,R,lson)); 52 if(R > m) 53 ans = max(ans,Query(L,R,rson)); 54 55 return ans; 56 } 57 58 59 60 int main() 61 { 62 int n,m,a,b; 63 while(~scanf("%d%d",&n,&m)) 64 { 65 Build(1,n,1); 66 while(m--) 67 { 68 char op[2]; 69 scanf("%s%d%d",op,&a,&b); 70 if(op[0] == ‘Q‘) 71 printf("%d\n",Query(a,b,1,n,1)); 72 else 73 Update(a,b,1,n,1); 74 } 75 } 76 return 0; 77 }
- hdu1394 Minimum Inversion Number
- 这里学习到了逆序数的求法,归并排序求,线段树,树状数组,点树
- 求逆序数的方法
- 1394方法总结
- 思路:每插入一个数,就进行一次询问并更新(询问当前线段树中比X小的数的个数,询问区间为[x,n-1])
- 注:因为插入的数不会有重复且为0到N-1,所以询问时应该是在区间[x,n-1]
- 关于逆序数递推:求出原序列的逆序数后,通过递推确定最小的逆序数
- 这里把一个数x移到末尾,比x小的数[0...x-1]共x个都在x的前面了 ,逆序数减少x
- 比x大的树[x+1...N-1]共n-1-x个都在x的前面了,逆序数增加n-1-x个
- 最后的逆序数变化为 res = res + n-1-x - x = res + n-1-2*x
- Query操作:区间求和 update操作:单调增减
- View Code
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define maxn 5555 6 #define CLR(a,b) memset(a,b,sizeof(a)) 7 #define lson l, m, rt << 1 8 #define mid(l,r) (l+r)>>1 9 #define rson m+1, r, rt << 1 | 1 10 11 12 int sum[maxn<<2]; 13 int x[maxn],n; 14 15 void PushUP(int rt) 16 { 17 sum[rt] = sum[rt<<1] + sum[rt<<1|1]; 18 } 19 20 21 void Update(int p,int l,int r,int rt) 22 { 23 if(l == r) 24 { 25 sum[rt]++; 26 return; 27 } 28 int m = mid(l,r); 29 if(p <= m) 30 Update(p,lson); 31 else 32 Update(p,rson); 33 PushUP(rt); 34 } 35 36 int Query(int L,int R,int l,int r,int rt) 37 { 38 if(L <= l && r <= R) 39 return sum[rt]; 40 int m = mid(l,r); 41 int ans = 0; 42 if(L <= m) 43 ans += Query(L,R,lson); 44 if(R > m) 45 ans += Query(L,R,rson); 46 return ans; 47 } 48 49 50 int main() 51 { 52 while(~scanf("%d",&n)) 53 { 54 CLR(sum,0); 55 int res = 0; 56 for(int i=0;i<n;i++) 57 { 58 scanf("%d",&x[i]); 59 res += Query(x[i],n-1,0,n-1,1); 60 Update(x[i],0,n-1,1); 61 } 62 int ret = res; 63 for(int i=0;i<n;i++) 64 { 65 res += n - 1 - x[i] - x[i]; 66 ret = min(ret,res); 67 } 68 printf("%d\n",ret); 69 } 70 71 return 0; 72 }
- hdu2795 Billboard
- 思路: 将h这一维映射到线段树的区间,w这一维对应区间点上的最大值,
- 每次询问的时候(询问先左后右),做一次插入的操作,相应的h维度的值减少wi
- 参考blog
- Query操作: 返回区间最大值的位置(hh大神直接把update写里面了)
- View Code
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 5 #define lson l, m, rt << 1 6 #define rson m+1, r, rt << 1 | 1 7 #define mid(l,r) (l+r) >> 1 8 #define maxn 222222 9 10 int MAX[maxn<<2]; 11 int h,w,n; 12 13 void PushUP(int rt) 14 { 15 MAX[rt] = max(MAX[rt<<1], MAX[rt<<1|1]); 16 } 17 18 void Build(int l,int r,int rt) 19 { 20 MAX[rt] = w; 21 if(l == r) 22 return; 23 int m = mid(l,r); 24 Build(lson); 25 Build(rson); 26 } 27 28 int Query(int x,int l,int r,int rt) 29 { 30 if(l == r) //找到可以放置的位置 31 { 32 MAX[rt] -= x; 33 return l; 34 } 35 int m = mid(l,r); 36 int ret = (MAX[rt<<1] >= x) ? Query(x,lson) : Query(x,rson); 37 PushUP(rt); 38 return ret; 39 } 40 41 int main() 42 { 43 while(~scanf("%d%d%d",&h,&w,&n)) 44 { 45 h = min(h,n); 46 Build(1,h,1); 47 while(n--) 48 { 49 int x; 50 scanf("%d",&x); 51 if(MAX[1] < x) puts("-1"); 52 else printf("%d\n",Query(x,1,h,1)); 53 } 54 } 55 return 0; 56 }
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。