当两个区间交叉的时候,他们是可以相互达到的
当我们每插入一个区间的时候,把和它交叉的所有区间缩成一个区间,即这个区间的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 second
using 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;
}