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
#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(""); } }
时间: 2024-11-10 05:23:23