题意:给你1e5个点(x,y,z),对于每一个点询问有多少个点(x1,y1,z1)满足x1<=x&&y1<=y&&z1<=z
分析:(官方题解奉上)很显然让你找(x,y,z)(x,y,z)都大于别的(x,y,z)(x,y,z),当然厉害的人可以用树套树水一下,但正解写的是CDQ分治,以xx为第一关键字排序,以yy为第二关键字来找,以zz为第三关键字建一个树状数组找就好了,当然等于的情况可以实现前做一下。
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <iostream> #include <algorithm> #include <map> #include <set> #include <stack> #include <queue> #include <string> using namespace std; typedef long long LL; const int maxn=1e5+5; struct BIT { int c[maxn]; void init() { memset(c,0,sizeof(c)); } int lowbit(int x) { return x&(-x); } void add(int x,int t) { while(x<=1e5) { c[x]+=t; x+=lowbit(x); } } int sum(int x) { int ans=0; while(x>0) { ans+=c[x]; x-=lowbit(x); } return ans; } } bit; struct Node { int x,y,z,id; } o[maxn],tem[maxn]; bool cmp(Node a,Node b) { if(a.x!=b.x) return a.x<b.x; if(a.y!=b.y) return a.y<b.y; return a.z<b.z; } bool cmp1(Node a,Node b) { return a.y<b.y; } int res[maxn]; void solve(int l,int r) { if(l==r)return; int m=(l+r)>>1; for(int i=l; i<=r; ++i) tem[i]=o[i]; sort(tem+l,tem+m+1,cmp1); sort(tem+m+1,tem+r+1,cmp1); int cnt=l; for(int i=m+1; i<=r; ++i) { while(cnt<=m&&tem[cnt].y<=tem[i].y)bit.add(tem[cnt].z,1),cnt++; res[tem[i].id]+=bit.sum(tem[i].z); } for(int i=l; i<cnt; ++i) bit.add(tem[i].z,-1); solve(l,m); solve(m+1,r); } int main() { int T,n; scanf("%d",&T); while(T--) { scanf("%d",&n); bit.init(); for(int i=1; i<=n; ++i) scanf("%d%d%d",&o[i].x,&o[i].y,&o[i].z),o[i].id=i; sort(o+1,o+1+n,cmp); memset(res,0,sizeof(res)); solve(1,n); for(int i=n-1; i>0; --i) if(o[i].x==o[i+1].x&&o[i].y==o[i+1].y&&o[i].z==o[i+1].z) res[o[i].id]=res[o[i+1].id]; for(int i=1; i<=n; ++i) printf("%d\n",res[i]); } return 0; }