当前位置: 代码迷 >> 综合 >> BZOJ 3262 陌上花开
  详细解决方案

BZOJ 3262 陌上花开

热度:93   发布时间:2023-12-15 07:55:44.0

题目

话说这是一道权限题,如果我复制过来,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].bfor(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;
}