题目
话说这是一道权限题,如果我复制过来,BZOJ不会打死我吧?hhh
http://www.lydsy.com/JudgeOnline/problem.php?id=3262
题解
大意就是给三维空间中的很多点,一个点p(x,y,z)的级别定义为x0<=x && y0<=y && z0<=z的任意点p0(x0,y0,z0)的数量,求每种级别的点各有多少种。
看过一道二维的这样的题目,当时想的是直接排序然后用BIT(树状数组)秒掉,题解给出了一种排序后用treap维护的方法(不涉及rotate),下面讲一讲这种方法(y为第一关键字,x为第二关键字排序)。
首先treap中的节点存两个值,x坐标和一个sz(等于左儿子的size+1)。将排序后的点一个一个往坐标系里加,在treap中从根节点开始往下走,(设当前点为p)因为排过序所以保证只要当前在p左边的点一定在p下方(这也就是用BIT可以做的原因),设当前在treap里走到的点为p1,答案为ans;
______________1,若p1.x>=p.x则说明p1的左边多了一个点,于是p1.sz++, 往左儿子走(其实我觉得是要往左儿子(以下简称lc)走才加的sz);
______________2,若p1.x<=p.x则说明p在p1右边,所以p1的左子树肯定都在p左边,ans+=p1.sz;
一直往下走,走到p1==NULL就停止,把p放进去,此时p.sz=1;
我一开始也没想明白;
1,p应该在很多点的左边,为什么处理了p1就往左走了?
2,如何做到不重不漏的?
想一想,把treap的根节点看做在坐标系中一根x=k的线,如果你在k右边,那么k左边的点数就等于k.sz,就统计完了;否则,往左走你又会碰到一个点,设为k1,又跟k1比较,一样的,这样不断移动,就能不重不漏统计完所有的点。
想到了什么?这跟BIT在本质上不是差不多吗?如果每次恰好分成两份,不就是一个活生生的BIT吗?但是treap有优点,节点少(后面非常有用),但是treap有缺点,它会被卡成一条链(出题人比较良心没卡我的裸treap)。二维解决完毕
怎么扩展到三维?排序,对;二维树状数组是不是一眼做?可是开不下,难道要treap套treap?好像没见过这玩意儿(废话我才第一次写树套树),那就BIT套treap。先扔掉一维,像上面一样,这一维没用,那么这就要求我们实现一个功能,单点修改,矩阵求和。(没有删除好像很关键?好像没删除是为了让整体二分过)于是外面BIT维护x轴,内层treap维护某个矩阵,就像原来的BIT的一个节点维护某一段区间一样。然后和二维差不多,外层BIT的循环照样写,只是修改的那一句话要写成treap的update。
这是树套树的第一篇所以写的很长,以后应该就是一句话题解了。
代码
//QWsin
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=100000+10;
const int maxv=200000+10;
inline int read()
{
int ret=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
for(;ch>='0'&&ch<='9';ch=getchar()) ret=ret*10+ch-'0';
return ret;
}
struct Hua{
int a,b,c;
inline void input(){
a=read();b=read();c=read();
}
bool operator < (const Hua &rhs)const{
if(a!=rhs.a) return a<rhs.a;
if(b!=rhs.b) return b<rhs.b;
return c<rhs.c;
}
bool operator == (const Hua &rhs)const{
return a==rhs.a&&b==rhs.b&&c==rhs.c;
}
}a[maxn];
namespace treap{
struct Node{
int lsz,y;
Node *lc,*rc;
Node(){
lsz=y=0;lc=rc=NULL;
}
Node(int lsz,int y):lsz(lsz),y(y){
lc=rc=NULL;
}
};
Node* root[maxv];
inline int query(int x,int y)
{
Node *cur=root[x];
int count=0;
while(cur!=NULL)
{
if(y >= cur->y) count+=cur->lsz,cur=cur->rc;
else cur=cur->lc;
}
return count;
}
inline void updata(int x,int y)
{
Node *cur=root[x],*fa=NULL;
int t=-1;
while(cur!=NULL)
{
fa=cur;
if(y <= cur->y)cur->lsz++,cur=cur->lc,t=0;
else if(y > cur->y)cur=cur->rc,t=1;
}
if(fa==NULL) root[x]=new Node(1,y);
else if(t) fa->rc=new Node(1,y);
else fa->lc=new Node(1,y);
}
}
int Maxx=0;
namespace BIT{
int C[maxv];
#define lowbit(x) ((x)&(-x))
inline int query(int x,int y)// query and insert
{
int ret=0;
for(;x;x-=lowbit(x)) ret+=treap::query(x,y);
return ret;
}
inline void updata(int x,int y){
for(;x<=Maxx;x+=lowbit(x)) treap::updata(x,y);
}
}
int ans[maxn],kind[maxn];
int main()
{
int n,k;cin>>n>>k;
for(int i=1;i<=n;i++) a[i].input(),Maxx=max(Maxx,a[i].c);
sort(a+1,a+n+1);
#define x a[i].c
#define y a[i].b
for(int i=1;i<=n;i++) {
kind[i]=BIT::query(x,y);
BIT::updata(x,y);
}
for(int i=1,cnt;i<=n;i+=cnt)//先标记kind,方便后面将同位置的点合并,同类的点的等级都跟他们中的最后一个一样
{
for(cnt=0;i+cnt<=n&&a[i]==a[i+cnt];cnt++);
ans[kind[i+cnt-1]]+=cnt;
}
for(int i=0;i<=n-1;i++) printf("%d\n",ans[i]);
return 0;
}