kd-tree 題目練習
阿新 • • 發佈:2018-11-22
kd tree原理詳解: KD-樹介紹
程式碼模板和部分題借鑑:kd-tree小結
例題一: P4475 巧克力王國
思路:根據巧克力a和可可b建立kd-tree,每個節點維護子樹的最大的a,b以及最小的a,b,一個子樹的權值和sum,每次查詢,如果四對極值點 a b滿足 x*a+y*b<h,那麼這顆子樹都可以對答案產生貢獻,直接返回sum,否則再判斷該節點是否滿足條件以及兩個兒子是否滿足條件,模板題。
#include<cstdio> #include<algorithm> using namespace std; typedef long long ll; const int maxn=5e5+10; int n,m,root,cur; ll a,b,c; struct P { int d[2],mx[2],mn[2],ls,rs,v; ll sum; int& operator[](int x){return d[x];} friend bool operator<(P a,P b){return a[cur]<b[cur];} }p[maxn]; struct kdtree { P t[maxn]; void up(int k) { int ls=t[k].ls,rs=t[k].rs; for(int i=0;i<2;i++) { t[k].mn[i]=t[k].mx[i]=t[k][i]; if(ls)t[k].mn[i]=min(t[k].mn[i],t[ls].mn[i]); if(rs)t[k].mn[i]=min(t[k].mn[i],t[rs].mn[i]); if(ls)t[k].mx[i]=max(t[k].mx[i],t[ls].mx[i]); if(rs)t[k].mx[i]=max(t[k].mx[i],t[rs].mx[i]); } t[k].sum=t[ls].sum+t[rs].sum+t[k].v; } int build(int l,int r,int now) { cur=now; int mid=(l+r)/2; nth_element(p+l,p+mid,p+r+1); t[mid]=p[mid]; if(l<mid)t[mid].ls=build(l,mid-1,!now); if(r>mid)t[mid].rs=build(mid+1,r,!now); up(mid); return mid; } int check(ll x,ll y) { return a*x+b*y<c; } int cal(P a) { int tmp=0; tmp+=check(a.mx[0],a.mx[1]); tmp+=check(a.mx[0],a.mn[1]); tmp+=check(a.mn[0],a.mx[1]); tmp+=check(a.mn[0],a.mn[1]); return tmp; } ll qu(int o) { int tmp=cal(t[o]); if(tmp==4) return t[o].sum; if(!tmp)return 0; ll res=0; if(check(t[o][0],t[o][1])) res+=t[o].v; if(t[o].ls)res+=qu(t[o].ls); if(t[o].rs)res+=qu(t[o].rs); return res; } }kd; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d%d%d",&p[i][0],&p[i][1],&p[i].v); root=kd.build(1,n,0); while(m--) { scanf("%lld%lld%lld",&a,&b,&c); printf("%lld\n",kd.qu(root)); } }
例題二:Hide and Seek
列舉所有點,再用kd-tree求該點到平面內距離最大的點以及最小的點只差即可,kd-tree經典模板題
#include<cstdio> #include<algorithm> #include<cmath> using namespace std; const int maxn=5e5+10,inf=1e9; int cur,n,root; struct P { int d[2],mx[2],mn[2],ls,rs; int& operator[](int x){return d[x];} friend bool operator<(P a,P b){return a[cur]<b[cur];} friend int dis(P x,P y) {return abs(x[0]-y[0])+abs(x[1]-y[1]);} }p[maxn]; struct kdtree { P t[maxn],T; int ans; void up(int o) { int ls=t[o].ls,rs=t[o].rs; for(int i=0;i<2;i++) { t[o].mn[i]=t[o].mx[i]=t[o][i]; if(ls)t[o].mn[i]=min(t[o].mn[i],t[ls].mn[i]); if(rs)t[o].mn[i]=min(t[o].mn[i],t[rs].mn[i]); if(ls)t[o].mx[i]=max(t[o].mx[i],t[ls].mx[i]); if(rs)t[o].mx[i]=max(t[o].mx[i],t[rs].mx[i]); } } int build(int l,int r,int now) { cur=now; int mid=(l+r)/2; nth_element(p+l,p+mid,p+r+1); t[mid]=p[mid]; if(l<mid)t[mid].ls=build(l,mid-1,!now); if(r>mid)t[mid].rs=build(mid+1,r,!now); up(mid); return mid; } int getv(int tp,P a) { int res=0; for(int i=0;i<2;i++) { if(!tp) res+=max(T[i]-a.mx[i],0)+max(a.mn[i]-T[i],0); else res+=max(abs(T[i]-a.mx[i]),abs(T[i]-a.mn[i])); } return res; } void qmin(int o) { if(dis(t[o],T))ans=min(ans,dis(t[o],T)); int ls=t[o].ls,rs=t[o].rs,t1=inf,t2=inf; if(ls)t1=getv(0,t[ls]); if(rs)t2=getv(0,t[rs]); if(t1<t2) { if(t1<ans)qmin(ls); if(t2<ans)qmin(rs); } else { if(t2<ans)qmin(rs); if(t1<ans)qmin(ls); } } void qmax(int o) { ans=max(ans,dis(t[o],T)); int ls=t[o].ls,rs=t[o].rs,t1=-inf,t2=-inf; if(ls)t1=getv(1,t[ls]); if(rs)t2=getv(1,t[rs]); if(t1>t2) { if(t1>ans)qmax(ls); if(t2>ans)qmax(rs); } { if(t2>ans)qmax(rs); if(t1>ans)qmax(ls); } } int qu(int tp,int x,int y) { T[0]=x,T[1]=y; if(tp)ans=-inf,qmax(root); else ans=inf,qmin(root); return ans; } }kd; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d%d",&p[i][0],&p[i][1]); root=kd.build(1,n,0); int ans=inf; for(int i=1;i<=n;i++) { int res=kd.qu(1,p[i][0],p[i][1])-kd.qu(0,p[i][0],p[i][1]); ans=min(ans,res); } printf("%d\n",ans); }