线段树专辑
来源:互联网 发布:大数据龙头公司 编辑:程序博客网 时间:2024/05/22 12:10
代码风格:
- maxn是题目给的最大区间,而节点数要开4倍,确切的来说节点数要开大于maxn的最小2x的两倍
- lson和rson分辨表示结点的左儿子和右儿子,由于每次传参数的时候都固定是这几个变量,所以可以用预定于比较方便的表示
- 以前的写法是另外开两个个数组记录每个结点所表示的区间,其实这个区间不必保存,一边算一边传下去就行,只需要写函数的时候多两个参数,结合lson和rson的预定义可以很方便
- PushUP(int rt)是把当前结点的信息更新到父结点
- PushDown(int rt)是把当前结点的信息更新给儿子结点
- rt表示当前子树的根(root),也就是当前所在的结点
hdu 1166
线段树功能:update:单点增减 query:区间求和
#include<stdio.h>#include<string.h>#include<stdlib.h>#define lson l , m , rt << 1#define rson m+1 , r , rt << 1 | 1const int maxn = 55555;int sum[maxn<<2];void PushUP(int rt){ sum[rt] = sum[rt<<1] + sum[rt<<1|1];}void build(int l,int r,int rt){ int m; if(l == r) { scanf("%d",&sum[rt]); return ; } m = (l + r) >> 1; build(lson); build(rson); PushUP(rt);}void update(int p,int add,int l,int r,int rt){ int m; if(l == r) { sum[rt] += add; return ; } m = (l + r) >> 1; if(p <= m) update(p,add,lson); else update(p,add,rson); PushUP(rt);}int query(int L,int R,int l,int r,int rt){ int m,ret; if(L <= l && r<=R) return sum[rt]; m = (l + r) >> 1; ret = 0; if(L <= m) ret += query(L,R,lson); if(R > m) ret += query(L,R,rson); return ret;}int main(){ int T,n,ncase,a,b; char op[10]; scanf("%d",&T); for(ncase=1;ncase<=T;ncase++) { scanf("%d",&n); build(1,n,1); printf("Case %d:\n",ncase); while(scanf("%s",&op)) { if(op[0] == 'E') break; scanf("%d%d",&a,&b); if(op[0] == 'Q') printf("%d\n",query(a,b,1,n,1)); else if(op[0] == 'S') update(a,-b,1,n,1); else update(a,b,1,n,1); } } return 0;}
hdu 1754 I hate it
#include<stdio.h>#include<string.h>#include<stdlib.h>#define lson l , m , rt<<1#define rson m+1 , r , rt<<1|1const int MAXN = 200010;int sum[MAXN<<2];int max(int a,int b){ return a > b ? a : b;}void PushUP(int rt){ sum[rt] = max(sum[rt<<1] , sum[rt<<1|1]);}void build(int l,int r,int rt){ int m; if(l == r) { scanf("%d",&sum[rt]); return ; } m = (l + r) >> 1; build(lson); build(rson); PushUP(rt);}int query(int L,int R,int l,int r,int rt){ int m,ans = 0; if(L <= l && r <= R) { return sum[rt]; } m = (l + r) >> 1; if(L <= m) ans = max(ans,query(L,R,lson)); if(R > m) ans = max(ans,query(L,R,rson)); return ans;}void update(int pos,int value,int l,int r,int rt){ int m; if(l == r) { sum[rt] = value; return ; } m = (l + r) >> 1; if(pos <= m) update(pos,value,lson); else update(pos,value,rson); PushUP(rt);}int main(){ int N,M,a,b,i; char op; while(~scanf("%d%d",&N,&M)) { build(1,N,1); getchar(); for(i = 0;i < M;i ++) { scanf("%c %d %d",&op,&a,&b); if(op == 'Q') printf("%d\n",query(a,b,1,N,1)); else update(a,b,1,N,1); getchar(); } } return 0;}
hdu 1394
题意:求Inversion后的最小逆序数
思路:用O(nlogn)复杂度求出最初逆序数后,就可以用O(1)的复杂度分别递推出其他解
线段树功能:update:单点增减 query:区间求和
#include<stdio.h>#include<string.h>#include<stdlib.h>#define lson l , m , rt << 1#define rson m+1 , r , rt << 1 | 1const int maxn = 5555;int sum[maxn<<2];void PushUP(int rt){ sum[rt] = sum[rt<<1] + sum[rt<<1|1];}void build(int l,int r,int rt){ int m; if(l == r) { sum[rt] = 0; return ; } m = (l + r) >> 1; build(lson); build(rson); PushUP(rt);}int query(int L,int R,int l,int r,int rt){ int m,ans = 0; if(L <= l && r <= R) return sum[rt]; m = (l + r) >> 1; if(L <= m) ans += query(L,R,lson); if(R > m) ans += query(L,R,rson); return ans;}void update(int pos,int value,int l,int r,int rt){ int m; if(l == r) { sum[rt] = value; return ; } m = (l + r) >> 1; if(pos <= m) update(pos,value,lson); else update(pos,value,rson); PushUP(rt);}int min(int a,int b){ return a > b ? b : a;}int x[maxn];int main(){ int n,i,sum,ans; while(~scanf("%d",&n)) { sum = 0; build(1,n,1); for(i = 0;i < n;i ++) { scanf("%d",&x[i]); sum += query(x[i] + 1,n,1,n,1); update(x[i] + 1,1,1,n,1); } ans = 10000000; for(i = 0;i < n;i ++) { sum += n - x[i] - x[i] -1; ans = min(sum,ans); } printf("%d\n",ans); } return 0;}
hdu 2795
这题有点DT,一开始我以为是一个复杂的DP,但是其实不是 == ,只要每次找到最大值的位子,然后减去L就可以了 =。=
比如,对于输入:
2 6 4
3/2/4/3
输出为:
1/1/2/-1,
而不是2/1/1/2 =。=
只是个贪心 = =
# include <stdio.h>#define lson l,m,rt << 1#define rson m + 1,r,rt << 1|1const int maxn = 200010;int MAX[maxn<<2];int h,w,n;int max(int a,int b){ return a > b ? a : b;}void PushUP(int rt){ MAX[rt] = max(MAX[rt << 1],MAX[rt << 1|1]);}void build(int l,int r,int rt){ int m; if(l == r) { MAX[rt] = w; return ; } m = (l + r) >> 1; build(lson); build(rson); PushUP(rt);}int query(int x,int l,int r,int rt){ int m,ans; if(l == r) { MAX[rt] -= x; return l; } m = (l + r) >> 1; ans = (MAX[rt << 1] >= x) ? query(x,lson) : query(x,rson); PushUP(rt); return ans;}int main(){ int i,x; while(~scanf("%d%d%d",&h,&w,&n)) { if(h > n) h = n; build(1,h,1); for(i = 0;i < n;i ++) { scanf("%d",&x); if(x > MAX[1]) puts("-1"); else printf("%d\n",query(x,1,h,1)); } } return 0;}
poj 2828
给定n个人进入队伍时的位置,如果某个位置及其后面有人,则后面的人都要向后挪一个位置,这不正是每天都在现实生活中上演的插队问题吗!有n个pos[i]和val[i],pos[i]表示这个人插入到pos[i]的右面,其实加1的话,更好理解,就是插在什么位置。至于那个val[i]只是为了表示某个人而已,理解成RP什么的都可以。
# include <stdio.h>#define lson l , m , rt<<1#define rson m+1 , r , rt<<1|1const int maxn = 200010;int empty[maxn<<2];int ans[maxn],pos[maxn],val[maxn];int index;void build(int l,int r,int rt){ int m; empty[rt] = r - l + 1; if(l == r) return ; m = (l + r) >> 1; build(lson); build(rson);}void update(int p,int l,int r,int rt){ int m; empty[rt] --; if(l == r) { index = l; return ; } m = (l + r) >> 1; if(empty[rt<<1] >= p) update(p,lson); else p -= empty[rt<<1],update(p,rson);}int main(){ int n,i; while(~scanf("%d",&n)) { build(1,n,1); for(i = 1;i <= n;i ++) scanf("%d%d",&pos[i],&val[i]); for(i = n;i >= 1;i --) update(pos[i]+1,1,n,1),ans[index] = val[i]; for (i = 1; i <= n; ++i) printf(i == n ? "%d\n" : "%d ",ans[i]); } return 0;}
- 线段树专辑(转)
- 线段树专辑(转)
- 线段树专辑(转)
- 【数据结构】线段树专辑
- [数据结构]线段树专辑
- 线段树专辑
- 【数据结构】线段树专辑
- [专辑]线段树总结[updating]
- ACM大牛总结的线段树专辑
- ACM_大牛总结的线段树专辑
- 简单线段树专辑(未完待续 poj3468+hdu1698+hdu4325+hdu1394+poj2777
- 树DP训练专辑
- 线段树?线段树!
- 线段树?线段树!
- 线段_线段树
- 线段_线段树
- 大长今专辑
- 一些专辑
- 成绩3
- 数据结构 线性表 循环链表 插入与删除
- Android 4.0 事件输入(Event Input)系统
- A转a
- 密码翻译
- 线段树专辑
- 北間島移住
- 第三章 操作符
- 【数组】14周项目六(一)。完整复制字符串
- Android 按键事件处理详解
- poj dp分类题目:
- Deep Learnin资料整理
- SharpKit 之移植 --I
- 字符串大统计【二】——统计字符串中的大小写字母个数