[KD树] BZOJ5005. 乒乓游戏
来源:互联网 发布:linux编译环境搭建 编辑:程序博客网 时间:2024/05/21 06:02
当两个区间交叉的时候,他们是可以相互达到的
当我们每插入一个区间的时候,把和它交叉的所有区间缩成一个区间,即这个区间的L为这些区间的L的最小值,R为这些区间的R的最大值
还有一种特殊情况,当我们插入一个区间时,如果它被之前的某个区间包含了,那么也要缩起来,因为题目保证新加入的区间长度一定大于之前的区间,那么如果它被某个区间包含了,那个区间一定是多个区间缩成的,这些区间一定会有一个区间和当前的区间交叉
那么现在就要找和它交叉的区间。
设当前区间为[L,R],那么要和它缩起来的区间[L1,R1]满足一下条件之一
L1 < L & L < R1 < R
L < L1 < R & R1 > R
L <= L1 & R1>= R
把区间看作点(L,R),那么每个条件对应二位平面内的一个矩形,用KD-TREE把这个矩形中的点提取出来,用并查集缩起来,每个点最多被提取一次,所以复杂度是
当然这样会被卡…那么就没
UPD:好像替罪羊式重构复杂度更优
#include <cstdio>#include <algorithm>#include <iostream>#include <set>#include <vector>#define fi first#define se secondusing namespace std;const int N=100010;int n,q,fa[N],l[N],r[N];inline char nc(){ static char buf[100000],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;}inline void read(int &x){ char c=nc(); x=0; int f=1; for(;c>'9'||c<'0';c=nc())if(c=='-') f=-1; for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc()); x*=f;}vector<int> v;namespace KDT{ struct Pt{ int x,y,maxx,maxy,minx,miny,used,g,size; Pt *l,*r; }pool[N],*t,*root; void dfs(Pt *cur){ if(!cur) return ; if(!cur->used) cur->used=1,v.push_back(cur->g); dfs(cur->l); dfs(cur->r); } inline void Up(Pt *x){ if(!x->used) x->maxx=x->minx=x->x,x->maxy=x->miny=x->y,x->size=1; else x->maxx=x->maxy=-1<<30,x->minx=x->miny=1<<30,x->size=0; if(x->l){ x->size+=x->l->size; x->maxx=max(x->l->maxx,x->maxx),x->minx=min(x->minx,x->l->minx); x->maxy=max(x->l->maxy,x->maxy),x->miny=min(x->miny,x->l->miny); } if(x->r){ x->size+=x->r->size; x->maxx=max(x->r->maxx,x->maxx),x->minx=min(x->minx,x->r->minx); x->maxy=max(x->r->maxy,x->maxy),x->miny=min(x->miny,x->r->miny); } } void Extract(Pt *&cur,int a,int b,int x,int y){ if(!cur) return ; if(cur->maxx<=x && cur->maxy<=y && cur->minx>=a && cur->miny>=b){ dfs(cur); cur=0; return ; } if(cur->maxx<a || cur->maxy<b || cur->minx>x || cur->miny>y) return ; if(cur->x>=a && cur->x<=x && cur->y>=b && cur->y<=y && !cur->used){ cur->used=1; v.push_back(cur->g); } Extract(cur->l,a,b,x,y); Extract(cur->r,a,b,x,y); Up(cur); } inline Pt *New(int x,int y,int g){ t->x=t->minx=t->maxx=x; t->y=t->miny=t->maxy=y; t->g=g; t->used=0; t->size=1; return t++; } Pt **Rb; int PP; inline int Size(Pt *cur){ if(!cur) return 0; return cur->size; } void Insert(Pt *&cur,Pt *x,int p=1){ if(!cur) { cur=x; return ; } if(p){ if(x->x>cur->x) Insert(cur->r,x,p^1); else Insert(cur->l,x,p^1); Up(cur); } else{ if(x->y>cur->y) Insert(cur->r,x,p^1); else Insert(cur->l,x,p^1); Up(cur); } if(Size(cur->l)*0.7>=Size(cur->r) || Size(cur->r)*0.7>=Size(cur->l)) Rb=&cur,PP=p; } Pt *r[N]; int tt; void dfs1(Pt *cur){ if(!cur) return ; if(!cur->used) r[++tt]=cur; dfs1(cur->l); dfs1(cur->r); } inline bool cmp(const Pt *a,const Pt *b){ if(PP) return a->x<b->x; else return a->y<b->y; } Pt *Build(int L,int R){ if(L>R) return 0; int mid=L+R>>1; Pt *ret; nth_element(r+L,r+mid,r+R+1,cmp); ret=r[mid]; PP^=1; ret->l=Build(L,mid-1); ret->r=Build(mid+1,R); Up(ret); return ret; } inline void rebuild(Pt *&cur){ tt=0; dfs1(cur); for(int i=1;i<=tt;i++) r[i]->l=r[i]->r=0; cur=Build(1,tt); } inline void Insert(int x,int y,int g){ Rb=0; Insert(root,New(x,y,g)); if(Rb) rebuild(*Rb); }}int Gfat(int x){ return x==fa[x]?x:fa[x]=Gfat(fa[x]);}int main(){ freopen("1.in","r",stdin); freopen("1.out","w",stdout); read(q); KDT::t=KDT::pool; while(q--){ int opt; read(opt); if(opt==1){ n++; fa[n]=n; read(l[n]); read(r[n]); v.clear(); KDT::Extract(KDT::root,-(1<<30),l[n]+1,l[n]-1,r[n]-1); KDT::Extract(KDT::root,l[n]+1,r[n]+1,r[n]-1,1<<30); KDT::Extract(KDT::root,-(1<<30),r[n],l[n],1<<30); for(int i=0;i<v.size();i++) fa[Gfat(v[i])]=n,l[n]=min(l[n],l[v[i]]),r[n]=max(r[n],r[v[i]]); KDT::Insert(l[n],r[n],n); //if(n%1000==0) KDT::rebuild(KDT::root); //KDT::Insert(KDT::root,l[n],r[n],n); } else{ int x,y; read(x); read(y); x=Gfat(x); y=Gfat(y); if(x==y || (l[x]>l[y] && l[x]<r[y]) || (r[x]>l[y] && r[x]<r[y])) puts("YES"); else puts("NO"); } } return 0;}
阅读全文
0 0
- [KD树] BZOJ5005. 乒乓游戏
- KD树(网易游戏笔试)
- KD树(网易游戏笔试)
- bnu1326 乒乓游戏 C语言版
- Java -- 乒乓球 乒乓弹球游戏
- KD树
- kd树
- KD树
- kd树
- KD树
- KD树
- KD树
- KD树
- kd树
- KD(kd tree)树介绍
- 我做的打乒乓游戏程序:
- 简易乒乓游戏的construct2制法
- 构造平衡kd树(kd tree)
- BP算法纯理论推导
- 欢迎使用CSDN-markdown编辑器
- SSL--VPN未分配虚拟ip地址问题
- unity基础,控制游戏目标
- 二分法专题-lintcode二分法问题解惑
- [KD树] BZOJ5005. 乒乓游戏
- 成绩处理
- 二叉树的简单介绍和二叉树的二叉链表存储表示
- Pycharm中添加2to3工具
- 学习记录一
- C++中友元的用法
- uva1637(记忆化搜索)
- 括号匹配问题
- C# Task 是什么?返回值如何实现? Wait如何实现