hdu 4417,poj 2104 划分树(模版)归并树(模版)
来源:互联网 发布:全球黑客攻击源码 编辑:程序博客网 时间:2024/05/22 02:17
这次是彻底把划分树搞明白了,与此同时发现了模版的重要性。写程序一个字符都不能错啊~~~
划分树详解:点击打开链接
题意:求一组数列中任意区间不大于h的个数。
这个题的做法是用二分查询 求给定区间内的中值再与K进行比较。
重点介绍划分树:
数据结构:
t[20][maxn] // 树结构,划分树存储
sum[20][maxn] // 记录该行[l,i] 中i到l有多少个存在左子树中
as[maxn] //原始数组排序后结果
#include <stdio.h>#include <string.h>#include <math.h>#include <bitset>#include <iostream>#include <algorithm> #define inf 0x3fffffff#define mid ((l+r)>>1)const int maxn=100000+100;typedef unsigned __int64 ull;using namespace std;int N,M;int t[30][maxn]; // 树结构,划分树存储int sum[30][maxn]; // 记录该行[l,i] 中i到l有多少个存在左子树中int as[maxn];//排序后数组//建树是依据上一层建立下一层,所以t[p+1][ls++]=t[p][i]; l==r判断的条件放在循环后是为了让每个元素都到最底层void build(int p,int l,int r){int ls=l,rs=mid+1;int lm=0,i;for(i=rs-1;i>=l;i--)// ls rs 左右子树开始的位置 lm 放入左子树的中值数目(避免中值过多树不平衡)if(as[i]==as[mid]) lm++;else break;for(i=l;i<=r;i++){if(i==l) sum[p][i]=0;//sum的计算若为初始则为0,注意这里的每行sum有多个分开的树else sum[p][i]=sum[p][i-1];if(t[p][i]==as[mid])if(lm) //将部分中值的数放入左边lm--,sum[p][i]++,t[p+1][ls++]=t[p][i];else t[p+1][rs++]=t[p][i];else if(t[p][i]<as[mid]) sum[p][i]++,t[p+1][ls++]=t[p][i];//小于中值放入左边else t[p+1][rs++]=t[p][i];//大于放入右边,sum与其无关}if(l==r) return;build(p+1,l,mid);build(p+1,mid+1,r);}/*在p层,[l,r]范围内查询[ql,qr]中第K大数l+s 跳过查询区间前放入左子树个数,l+sum[p][qr]-1 [l,qr]放入左子树的个数ql-l-s 查询区间前放入右子树的个数,qr-l-sum[p][qr] [l,qr]放入右子树的个数*/int query(int p,int l,int r,int ql,int qr,int k){if(l==r) return t[p][l];int s,ss;//s是ql左边有多少放入下层左子树,ss是[ql,qr]中有多少放入下层左子树if(ql==l)s=0,ss=sum[p][qr];elses=sum[p][ql-1],ss=sum[p][qr]-s;if(k<=ss)return query(p+1,l,mid,l+s,l+sum[p][qr]-1,k);elsereturn query(p+1,mid+1,r,mid+1+ ql-l-s,mid+1 +qr-l-sum[p][qr],k-ss);}int main(){ int T; int n,m,cas=1;int i,l,r,k; scanf("%d",&T);while(T--){scanf("%d%d",&N,&M);for(i=0;i<N;i++)scanf("%d",as+i),t[0][i]=as[i];sort(as,as+N);build(0,0,N-1);printf("Case %d:\n",cas++);for(i=0;i<M;i++){scanf("%d%d%d",&l,&r,&k);int mi=1,ma=r-l+1,Mid,ans=r-l+2; while(mi<=ma) { Mid=(mi+ma)>>1; int tmp=query(0,0,N-1,l,r,Mid); if(tmp>k) { ans=Mid; ma=Mid-1; } else mi=Mid+1; } printf("%d\n",ans-1);}} return 0;}
归并树:
就是在归并过程中保存结果,因为归并排序与线段树建树类似都是自底向上,所以可以保存。(这个比划分树好理解多了)
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<map> #include<stack> #include<algorithm> #include<string> #define LL long long #define LD long double #define eps 1e-7 #define inf 1<<30 #define MOD 1000000007 #define N 100005 using namespace std; struct MergeTree{ int left,right,mid; }tree[N*4]; int num[N],mer[20][N]; int n,q; void create(int step,int l,int r,int deep){ tree[step].left=l; tree[step].right=r; tree[step].mid=(l+r)>>1; if(l==r){ mer[deep][l]=num[l]; return; } create(step<<1,l,(l+r)/2,deep+1); create((step<<1)|1,(l+r)/2+1,r,deep+1); int i=l,j=(l+r)/2+1,p=l; //归并排序,在建树的时候保存 while(i<=(l+r)/2&&j<=r){ if(mer[deep+1][i]>mer[deep+1][j]) mer[deep][p++]=mer[deep+1][j++]; else mer[deep][p++]=mer[deep+1][i++]; } while(i<=(l+r)/2) mer[deep][p++]=mer[deep+1][i++]; while(j<=r) mer[deep][p++]=mer[deep+1][j++]; } int query(int step,int l,int r,int deep,int key){ if(tree[step].right<l||tree[step].left>r) return 0; if(tree[step].left>=l&&tree[step].right<=r) //找到key在排序后的数组中的位置 return lower_bound(&mer[deep][tree[step].left],&mer[deep][tree[step].right]+1,key)-&mer[deep][tree[step].left]; return query(2*step,l,r,deep+1,key)+query(2*step+1,l,r,deep+1,key); } int slove(int l,int r,int k){ int high=n,low=1,mid; //二分答案 while(low<high){ mid=(low+high+1)>>1; int cnt=query(1,l,r,1,mer[1][mid]); if(cnt<=k) low=mid; else high=mid-1; } return mer[1][low]; } int main(){ while(scanf("%d%d",&n,&q)!=EOF){ for(int i=1;i<=n;i++) scanf("%d",&num[i]); create(1,1,n,1); while(q--){ int l,r,k; scanf("%d%d%d",&l,&r,&k); printf("%d\n",slove(l,r,k-1)); } } return 0; }
0 0
- hdu 4417,poj 2104 划分树(模版)归并树(模版)
- 划分树模版
- 归并排序(模版)
- hdu 2665 (poj 2104) 划分树
- POJ 2104&2761 主席树模版
- 快排法(模版型)与归并法
- POJ-2421(最小生成树模版)(Constructing Roads )
- poj 2001 Shortest Prefixes 字典树(模版题)
- POJ 2104 归并树 or 划分树
- POJ 2104 归并树 OR 划分树
- hdu 1251 统计难题(字典树模版)
- hdu 3074 Multiply game(线段树模版)
- HDU 1754 I Hate It(线段树模版)
- HDU 1251 统计难题(字典树模版)
- hdu 1247 Hat’s Words (字典树模版)
- 伸展树模版题 hdu
- hdu 1247 字典树模版
- 字典树(讲解+模版)
- 堆和栈的区别
- C语言中 %p的含义
- ACM算法列表
- POJ2762-Going from u to v or from v to u?(强连通缩点+DP)
- android intent uri汇总
- hdu 4417,poj 2104 划分树(模版)归并树(模版)
- 黑马程序员-----代理模式
- ubuntu10.04中没有eth0,只有eth1和eth2
- 在ASP.Net中"../" "./" "~/"表示什么意思
- 直立车调试指南,自己写的,我觉得对初学者还是有很大帮助的。。
- jplayer 实战
- C# 两窗体间控件调用
- The Psychology of Cross Country——绕圈心理学
- 解决DLL导出函数的名字改编问题