BZOJ 3262 陌上花开
来源:互联网 发布:中国战斗力知乎 编辑:程序博客网 时间:2024/06/02 19:36
题目
话说这是一道权限题,如果我复制过来,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;}
- 【bzoj 3262】: 陌上花开
- bzoj 3262: 陌上花开
- 【BZOJ 3262】 陌上花开
- bzoj 3262: 陌上花开
- BZOJ 3262 陌上花开
- BZOJ 3262 陌上花开
- BZOJ 3262 陌上花开
- 【bzoj 3262】陌上花开
- bzoj 3262 陌上花开
- BZOJ 3262 陌上花开
- BZOJ 3262 陌上花开 “树套树”
- BZOJ 3262 陌上花开 [树套树]
- BZOJ 3262: 陌上花开 CDQ
- BZOJ 3262 陌上花开 CDQ分治
- BZOJ 3262: 陌上花开 CDQ分治
- BZOJ 3262 陌上花开(CDQ分治)
- bzoj 3262: 陌上花开 【cdq分治】
- bzoj 3262: 陌上花开(cdq分治)
- hdoj1312Red and Black
- scanf/fscanf 的%[]和%n使用方法
- javascript常见的设计模式
- STL中用ERASE()方法遍历删除元素
- 在 Android 应用中使用自定义证书的 HTTPS 连接(下)
- BZOJ 3262 陌上花开
- jquery中选择器的用法
- 蓝桥杯Anagrams问题题解
- Wireshark入门与进阶系列一之基本使用
- 国内外blog
- Hive1.2.1安装
- Online Judge编程注意事项整理
- Rails(栈和队列简单应用)
- jQuery 绑定 select 联动 手动触发