第一次接触,自己也没啥好总结的,都是看网上的资料。
归并树是在建树的过程中保存归并排序。
划分树是在建树的过程中保存快速排序。
其中归并树适合解决一个数在某个区间的名次。
划分树适合解决某个区间的K大数。
POJ这题是找K大数,归并树也可做,二分答案,再由归并树找出这个数的名次。划分树更快。
对于HDU 2665,我写的归并树总之是过不去。
归并树:
[cpp]
#include
#include
#include
#include
#include
划分树:
[cpp]
#include
#include
#include
#include
#define N 100005
using namespace std;
struct Node{
int left,right,mid;
}tree[N*4];
int sa[N],num[20][N],cnt[20][N]; //sa中是排序后的,num记录每一层的排序结果,cnt[deep][i]表示第deep层,前i个数中有多少个进入左子树
int n,q;
void debug(int d){
for(int i=1;i<=n;i++)
printf("%d ",num[d][i]);
printf("\n");
}
void bulid(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)
return;
int mid=(l+r)>>1;
int mid_val=sa[mid],lsum=mid-l+1;;
for(int i=l;i<=r;i++)
if(num[deep][i]
int L=l,R=mid+1;
for(int i=l;i<=r;i++){
if(i==l)
cnt[deep][i]=0;
else
cnt[deep][i]=cnt[deep][i-1];
if(num[deep][i]
num[deep+1][L++]=num[deep][i];
cnt[deep][i]++;
if(num[deep][i]==mid_val)
lsum--;
}
else
num[deep+1][R++]=num[deep][i];
}
// debug(deep);
bulid(2*step,l,mid,deep+1);
bulid(2*step+1,mid+1,r,deep+1);
}
int query(int step,int l,int r,int k,int deep){
if(l==r)
return num[deep][l];
int s1,s2; //s1为[tree[step].left,l-1]中分到左子树的个数
if(tree[step].left==l)