您的位置:首页 > 其它

BZOJ 3262 陌上花开 树套树 (CDQ分治)

2017-02-27 19:07 471 查看
题目大意:有n个三元组(a,b,c)。定义一个三元组A大于另一个三元组B当且仅当A的三个元素都不小于B的三个元素.统计出大于(0~n-1)个三元组的数量。

有三个元素,首先用排序把a弄掉,对于(b,c)两个元素可以看做是平面上的点,利用树套树第一维树状数组,第二维Treap可以解决查找平面上在一个点左下方的点的个数。

当然也可以用CDQ分治来解决,要比树套树快很多(然而我就是喜欢树套树)

#include <cstdio>
#include <algorithm>
#define N 100005
using namespace std;
int n,m;
struct Flower {
int a,b,c;
void scan() {scanf("%d%d%d",&a,&b,&c);}
bool operator < (const Flower& rhs) const {
if(a!=rhs.a) return a<rhs.a;
if(b!=rhs.b) return b<rhs.b;
return c<rhs.c;
}
}a
;
int ans
,sum
;
struct Node {
Node *ch[2];
int s,r,v,cnt;
Node(int,int);
Node(){}
void maintain(){s=ch[0]->s+ch[1]->s+cnt;}
int cmp(int x){
if(x==v) return -1;
return x<v ? 0 : 1;
}
}*null,*root[N*2];
Node :: Node(int x,int y):r(x),v(y){s=null ? 1 : 0; ch[0]=ch[1]=null; cnt=s;}
void Rotate(Node*& o,int d) {
Node* k=o->ch[d^1];
o->ch[d^1]=k->ch[d];
k->ch[d]=o;
o->maintain(); k->maintain();
o=k;
return ;
}
void Insert(Node*& o,int x) {
int d=o->cmp(x);
if(o==null) o=new Node(rand(),x);
else if(d==-1) o->cnt++ , o->s++;
else {
Insert(o->ch[d],x); o->maintain();
if(o->ch[d]->r > o->r) Rotate(o,d^1);
}
return ;
}
int Rank(Node* o,int x) {
if(o==null) return 0;
int d=o->cmp(x);
if(d==-1) return o->ch[0]->s+o->cnt;
return Rank(o->ch[d],x)+ (d==1 ? o->ch[0]->s+o->cnt : 0);
}
inline int lowbit(int x) {return x&-x;}
void change(int x,int y) {
for(int i=x;i<=m;i+=lowbit(i)) Insert(root[i],y);
return ;
}
int query(int x,int y) {
int tmp=0;
for(int i=x;i;i-=lowbit(i)) tmp+=Rank(root[i],y);
return tmp;
}
int main() {
null=new Node(0,0);
scanf("%d%d",&n,&m);
for(int i=0;i<=m;i++) root[i]=null;
for(int i=1;i<=n;i++) a[i].scan();
sort(a+1,a+1+n);
for(int i=1;i<=n;i++) {
if(a[i].a==a[i+1].a && a[i].b==a[i+1].b && a[i].c==a[i+1].c && i!=n) sum[i+1]+=sum[i]+1;
else {
int tmp=query(a[i].b,a[i].c);
ans[tmp]+=sum[i]+1;
}
change(a[i].b,a[i].c);
}
for(int i=0;i<n;i++) printf("%d\n",ans[i]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: