(本人本题完成于2016-7-20)
题目大意:对于一些人,每个人有3个值:身高H,活跃度A,缘分值L,其中A和L为浮点数。有两种操作:1.往已有的人中增加一个人。2.在已有的人中找身高和活跃度均在指定区间内的人的缘分值的最大值,若找不到满足条件的人则输出-1。所有输入的浮点数均只有一位小数。
做法:基础的二维线段树,先建一棵以身高作为区间的母树,对母树的每一个节点再建一棵以活泼度作为区间的子树,插入和询问操作再稍微做一些改变,分为对母树的操作和对子树的操作两种。由于活泼度是浮点数,所以要将它乘10后再进行处理(注意:可能有浮点误差)。还要注意,题目中并没有给定查询区间的端点之间的大小关系,因此要做特殊处理。
以下为本人代码:
#include <cstdio> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; int M; char c; struct subnode { int l,r; int m; }; //子树节点 struct node { int l,r; subnode s[3010]; //母树内包含子树 }seg[310]; //母树节点 void buildsubtree(int no,int n,int l,int r) { int mid=(l+r)/2; seg[no].s[n].l=l; seg[no].s[n].r=r; seg[no].s[n].m=-1; //赋初值为负数,用来区分缘分值为0和无解两种情况 if (l==r) return; else { buildsubtree(no,2*n,l,mid); buildsubtree(no,2*n+1,mid+1,r); } } //建立子树 void buildtree(int no,int l,int r) { int mid=(l+r)/2; seg[no].l=l;seg[no].r=r; buildsubtree(no,1,0,1000); if (l!=r) { buildtree(2*no,l,mid); buildtree(2*no+1,mid+1,r); } } //建立母树 void subinsert(int no,int n,int a,int l) { int mid=(seg[no].s[n].l+seg[no].s[n].r)/2; if (seg[no].s[n].l==seg[no].s[n].r) seg[no].s[n].m=max(seg[no].s[n].m,l); else { if (a<=mid) subinsert(no,2*n,a,l); else subinsert(no,2*n+1,a,l); seg[no].s[n].m=max(seg[no].s[n].m,l); } } //对子树的插入操作 void insert(int no,int h,int a,int l) { int mid=(seg[no].l+seg[no].r)/2; subinsert(no,1,a,l); if (seg[no].l!=seg[no].r) { if (h<=mid) insert(2*no,h,a,l); else insert(2*no+1,h,a,l); } } //对母树的插入操作 int subquery(int no,int n,int la,int ra) { int mid=(seg[no].s[n].l+seg[no].s[n].r)/2; if (seg[no].s[n].l>=la&&seg[no].s[n].r<=ra) return seg[no].s[n].m; else { int ans=-1; if (la<=mid) ans=max(ans,subquery(no,2*n,la,ra)); if (ra>mid) ans=max(ans,subquery(no,2*n+1,la,ra)); return ans; } } //对子树的询问操作 int query(int no,int lh,int rh,int la,int ra) { int mid=(seg[no].l+seg[no].r)/2; if (seg[no].l>=lh&&seg[no].r<=rh) return subquery(no,1,la,ra); else { int ans=-1; if (lh<=mid) ans=max(ans,query(2*no,lh,rh,la,ra)); if (rh>mid) ans=max(ans,query(2*no+1,lh,rh,la,ra)); return ans; } } //对母树的询问操作 int main() { scanf("%d ",&M); while(M!=0) { buildtree(1,100,200); for(int i=1;i<=M;i++) { scanf("%c",&c); if (c=='I') { int h;double a,l; scanf("%d %lf %lf ",&h,&a,&l); insert(1,h,(int)(a*10+0.5),(int)(l*10+0.5)); //可能产生浮点误差,要进行四舍五入取整 } if (c=='Q') { int lh,rh,ans;double la,ra; scanf("%d %d %lf %lf ",&lh,&rh,&la,&ra); if (lh>rh) {int t=lh;lh=rh;rh=t;} if (la>ra) {double t=la;la=ra;ra=t;} //未确定区间端点的大小关系,需进行特殊处理 ans=query(1,lh,rh,(int)(la*10+0.5),(int)(ra*10+0.5)); if (ans>=0) printf("%d.%d ",ans/10,ans%10); else printf("-1 "); //无解处理 } } scanf("%d ",&M); } return 0; }