http://acm.hdu.edu.cn/showproblem.php?pid=3473

划分树模板题目,需要注意的是划分树的k是由1开始的

划分树:

参考:http://blog.csdn.net/shiqi_614/article/details/8041390

划分树的定义

划分树定义为,它的每一个节点保存区间[lft,rht]所有元素,元素顺序与原数组(输入)相同,但是,两个子树的元素为该节点所有元素排序后(rht-lft+1)/2个进入左子树,其余的到右子树,同时维护一个num域,num[i]表示lft->i这个点有多少个进入了左子树。

划分树的Sample

HDU 3473 Minimum Sum 划分树,数据结构 难度:1-LMLPHP

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
const int maxf=20;
int order[maxn];
int v[maxf][maxn];
ll s[maxn];
ll sum[maxf][maxn],asum;
int num[maxf][maxn];
void build(int l,int r,int ind){
if(l==r)return ;
int mid=(l+r)>>1;
int ln=l,rn=mid+1,same=mid-l+1;
for(int i=l;i<=r;i++){
if(v[ind][i]<order[mid])same--;
}
for(int i=l;i<=r;i++){
int flag=0;
if(v[ind][i]==order[mid]&&same>0){
same--;
flag=1;
v[ind+1][ln++]=v[ind][i];
sum[ind][i]=(i>0?sum[ind][i-1]:0)+v[ind][i];
}
else if(v[ind][i]<order[mid]){
flag=1;
v[ind+1][ln++]=v[ind][i];
sum[ind][i]=(i>0?sum[ind][i-1]:0)+v[ind][i];
}
else {
sum[ind][i]=i>0?sum[ind][i-1]:0;
v[ind+1][rn++]=v[ind][i];
}
num[ind][i]=(i>0?num[ind][i-1]:0)+flag;
}
build(l,mid,ind+1);
build(mid+1,r,ind+1);
}
int query(int s,int e,int k,int l,int r,int ind){
if(l==r)return v[ind][l];
int mid=(l+r)>>1;
int lls=num[ind][s-1]-num[ind][l-1];
int lse=num[ind][e]-num[ind][s-1];
int rls=s-l-lls;
int rse=e-s-lse+1;
if(lse>=k)return query(l+lls,l+lls+lse-1,k,l,mid,ind+1);
asum+=sum[ind][e]-(s>0?sum[ind][s-1]:0);
return query(mid+1+rls,mid+rls+rse,k-lse,mid+1,r,ind+1);
}
int main(){
int T;
scanf("%d",&T);
for(int t=1;t<=T;t++){
int n;
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&v[0][i]);
order[i]=v[0][i];
s[i]=(i>0?s[i-1]:0)+v[0][i];
}
sort(order,order+n);
memset(num,0,sizeof(num));
build(0,n-1,0);
int q;
scanf("%d",&q);
printf("Case #%d:\n",t);
for(int i=0;i<q;i++){
int l,r;
scanf("%d%d",&l,&r);
asum=0;
ll mid=query(l,r,((l+r)>>1)-l+1,0,n-1,0);
ll ans=mid*(((l+r)>>1)-l)-(r-((l+r)>>1))*mid-asum+(s[r]-(l>0?s[l-1]:0)-asum-mid);
printf("%I64d\n",ans);
}
puts("");
}
}

  

05-11 11:26