[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把这个矩形中的点提取出来,用并查集缩起来,每个点最多被提取一次,所以复杂度是 O(nn)

当然这样会被卡…那么就没 n 次操作后暴力重构一下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;}
原创粉丝点击