菜鸟系列——划分树
来源:互联网 发布:生辰八字起名软件2017 编辑:程序博客网 时间:2024/06/06 08:44
做回菜鸟,老老实实重新学起:
划分树
数据结构;
求k大值及左右和模版:
#define N 123456int sorted[N]={0}; //对原集合中元素排序后的值int val[20][N]={0}; //val记录第k层当前位置的值int num[20][N]={0}; //记录元素所在区间当前位置前的元素进入到左子树的个数int lnum, rnum; //询问区间里面k-th数左侧和右侧的数的个数long long sum[20][N]={0}; //记录比当前元素小的元素的和long long lsum, rsum; //询问区间里面k-th数左侧数之和与右侧数之和void build(int l, int r, int d){ if (l == r) return ; int mid = (l + r) >> 1; int same = mid - l + 1; for (int i=l; i<=r; i++) if (val[d][i] > sorted[mid]) same--; int lp = l, rp = mid+1; for (int i=l; i<=r; i++) { if (i == l) { num[d][i] = 0; sum[d][i] = 0; } else { num[d][i] = num[d][i-1]; sum[d][i] = sum[d][i-1]; } if (val[d][i] > sorted[mid]) { num[d][i]++; sum[d][i] += val[d][i]; val[d+1][lp++] = val[d][i]; } else if (val[d][i] < sorted[mid]) val[d+1][rp++] = val[d][i]; else { if (same) { same--; num[d][i]++; sum[d][i] += val[d][i]; val[d+1][lp++] = val[d][i]; } else val[d+1][rp++] = val[d][i]; } } build(l, mid, d+1); build(mid+1, r, d+1);}int query(int a, int b, int k, int l, int r, int d){ if (a == b) return val[d][a]; int mid = (l + r) >> 1; int s, ss; long long sss; if (a == l) { s = num[d][b]; ss = 0; sss = sum[d][b]; } else { s = num[d][b] - num[d][a-1]; ss = num[d][a-1]; sss = sum[d][b] - sum[d][a-1]; } if (s >= k) { a = l + ss; b = l + ss + s - 1; return query(a, b, k, l, mid, d+1); } else { lnum += s; lsum += sss; a = mid+1 + a - l - ss; b = mid+1 + b - l - num[d][b]; return query(a, b, k-s, mid+1, r, d+1); }}bool cmp(int a,int b){ return a>b; }void solve(int n,int m){ long long s[N]={0}; for(int i=1;i<=n;i++) { scanf("%d",&sorted[i]); val[0][i] = sorted[i]; s[i] = s[i-1] + sorted[i]; } printf("\n"); sort(sorted+1,sorted+1+n,cmp); build(1,n,0); int x,y,k,res; while(m--) { scanf("%d%d%d",&x,&y,&k); lsum = lnum = 0; res = query(x,y,k,1,n,0); printf("%d ",res); //输出第k大值 rnum = y-x+1 - lnum; rsum = s[y] - s[x-1] - lsum - res; printf("%lld %lld\n",lsum,rsum); //区间内比第k大值小的和大的值的和; }}
eg:
题目参考:http://blog.csdn.net/yang_7_46/article/details/8613461
POJ 2104 k-th number
http://poj.org/problem?id=2104
题意:
求区间内k小值;
思路:
直接划分树,求第k小值;
code:
#define N 123456int sorted[N]={0};int val[20][N]={0};int num[20][N]={0};int lnum, rnum;long long sum[20][N]={0};long long lsum, rsum;void build(int l, int r, int d){ if (l == r) return ; int mid = (l + r) >> 1; int same = mid - l + 1; for (int i=l; i<=r; i++) if (val[d][i] < sorted[mid]) same--; int lp = l, rp = mid+1; for (int i=l; i<=r; i++) { if (i == l) { num[d][i] = 0; sum[d][i] = 0; } else { num[d][i] = num[d][i-1]; sum[d][i] = sum[d][i-1]; } if (val[d][i] < sorted[mid]) { num[d][i]++; sum[d][i] += val[d][i]; val[d+1][lp++] = val[d][i]; } else if (val[d][i] > sorted[mid]) val[d+1][rp++] = val[d][i]; else { if (same) { same--; num[d][i]++; sum[d][i] += val[d][i]; val[d+1][lp++] = val[d][i]; } else val[d+1][rp++] = val[d][i]; } } build(l, mid, d+1); build(mid+1, r, d+1);}int query(int a, int b, int k, int l, int r, int d) { if (a == b) return val[d][a]; int mid = (l + r) >> 1; int s, ss; long long sss; if (a == l) { s = num[d][b]; ss = 0; sss = sum[d][b]; } else { s = num[d][b] - num[d][a-1]; ss = num[d][a-1]; sss = sum[d][b] - sum[d][a-1]; } if (s >= k) { a = l + ss; b = l + ss + s - 1; return query(a, b, k, l, mid, d+1); } else { lnum += s; lsum += sss; a = mid+1 + a - l - ss; b = mid+1 + b - l - num[d][b]; return query(a, b, k-s, mid+1, r, d+1); }}bool cmp(int a,int b){ return a<b; }void solve(int n,int m){ for(int i=1;i<=n;i++) { scanf("%d",&sorted[i]); val[0][i] = sorted[i]; } sort(sorted+1,sorted+1+n,cmp); build(1,n,0); int x,y,k,res; while(m--) { scanf("%d%d%d",&x,&y,&k); res = query(x,y,k,1,n,0); printf("%d\n",res); }}int main() { int n, m; #ifndef ONLINE_JUDGE freopen("test.txt","r",stdin); #endif scanf("%d%d",&n,&m); solve(n,m); return 0;}
HDU 3473 Minimum Sum
http://acm.hdu.edu.cn/showproblem.php?pid=3473
题意:
求区间内sum(x-xi)的最小值;x属于该区间;
思路:
找到区间内中位数即可,求区间内中位数,记录区间内大于和小于中位数的数的和,差值加减多余的中位数的值就是答案了;
code:
#define N 123456int sorted[N]={0};int val[20][N]={0};int num[20][N]={0};int lnum, rnum;long long sum[20][N]={0};long long lsum, rsum;void build(int l, int r, int d){ if (l == r) return ; int mid = (l + r) >> 1; int same = mid - l + 1; for (int i=l; i<=r; i++) if (val[d][i] < sorted[mid]) same--; int lp = l, rp = mid+1; for (int i=l; i<=r; i++) { if (i == l) { num[d][i] = 0; sum[d][i] = 0; } else { num[d][i] = num[d][i-1]; sum[d][i] = sum[d][i-1]; } if (val[d][i] < sorted[mid]) { num[d][i]++; sum[d][i] += val[d][i]; val[d+1][lp++] = val[d][i]; } else if (val[d][i] > sorted[mid]) val[d+1][rp++] = val[d][i]; else { if (same) { same--; num[d][i]++; sum[d][i] += val[d][i]; val[d+1][lp++] = val[d][i]; } else val[d+1][rp++] = val[d][i]; } } build(l, mid, d+1); build(mid+1, r, d+1);}int query(int a, int b, int k, int l, int r, int d) { if (a == b) return val[d][a]; int mid = (l + r) >> 1; int s, ss; long long sss; if (a == l) { s = num[d][b]; ss = 0; sss = sum[d][b]; } else { s = num[d][b] - num[d][a-1]; ss = num[d][a-1]; sss = sum[d][b] - sum[d][a-1]; } if (s >= k) { a = l + ss; b = l + ss + s - 1; return query(a, b, k, l, mid, d+1); } else { lnum += s; lsum += sss; a = mid+1 + a - l - ss; b = mid+1 + b - l - num[d][b]; return query(a, b, k-s, mid+1, r, d+1); }}bool cmp(int a,int b){ return a<b; }void solve(int n,int m){ long long s[N]={0}; for(int i=1;i<=n;i++) { scanf("%d",&sorted[i]); val[0][i] = sorted[i]; s[i] = s[i-1] + sorted[i]; } scanf("%d",&m); sort(sorted+1,sorted+1+n,cmp); build(1,n,0); int x,y,k,res; while(m--) { scanf("%d%d",&x,&y); x++,y++; k = (y-x+2)>>1; lsum = lnum = 0; res = query(x,y,k,1,n,0); rnum = y-x+1 - lnum; rsum = s[y] - s[x-1] - lsum; printf("%lld\n",(long long)(rsum-lsum+(lnum-rnum)*res)); //区间内比第k大值小的和大的值的和; } printf("\n");}int main(){ int k,kk,n,m; #ifndef ONLINE_JUDGE freopen("test.txt","r",stdin); #endif scanf("%d",&k); kk=0; while(k--) { printf("Case #%d:\n",++kk); scanf("%d",&n); solve(n,0); } return 0;}
0 0
- 菜鸟系列——划分树
- 菜鸟系列——线段树
- 菜鸟系列——字典树
- 菜鸟系列——最小生成树
- 菜鸟系列——KMP
- 菜鸟系列——搜索
- 菜鸟系列——Sparse Table
- 菜鸟系列——回文串
- 菜鸟系列——最短路
- 菜鸟系列——强连通分量
- 菜鸟系列——二分图匹配
- 菜鸟系列——置换群
- 菜鸟系列——polya计数法
- 菜鸟系列——欧拉函数
- 菜鸟系列——约瑟夫环
- 菜鸟系列——容斥原理
- 菜鸟系列——双连通分量
- 菜鸟系列——康托展开
- kafka技术分享系列(目录索引)
- Mysql DELETE删除除了最新的1000条记录的写法
- php面向对象基础概念(接口)
- 开源视频会议bigbluebutton开发(4)——构建开发环境,客户端开发
- 开源视频会议bigbluebutton开发(5)——开发web端,red5应用,桌面共享
- 菜鸟系列——划分树
- SGU144 Meeting
- oracle书籍推荐
- Python Show-Me-the-Code 第 0022 题 批量图片处理2
- 学习Python5(Thread)
- portaudio
- 虚拟机备份转移后,网络启动异常,提示“SIOCSIFADDR: No such device”的解决方案
- StrongReference, SoftReference, WeakReference 图解说明
- template