[BZOJ KDT] 5005: 乒乓游戏

1 篇文章 0 订阅

题目描述

Statement
下面这个有关区间的游戏,我们称之为“乒乓游戏”。
乒乓游戏可不是乒乓!乒乓好像也和这个游戏没啥关系。这个游戏的主角就
是——区间。对于两个区间,如果(a,b)和(c,d)区间满足 c<a<d 或者 c<b<d,就
可以从(a,b)到(c,d)去。现在有以下两种操作:
1 x y:(x<y)表示在区间集合中添加(x,y)这个区间,保证新加入的区间长
度一定比之前的所有区间长度长;
2 a b:(a≠b)表示询问是否有一条路从第 a 个区间到第 b 个区间。
游戏开始前,区间集合为空。现在,请你来回答所有的询问。
Input
第一行一个整数 N,表示操作的数目;
接下来 N 行,每行三个整数,表示一个操作。
Output
对每个询问操作,输出一行字符串,若可以请输出“YES”,否则输出“NO”,
不包括引号。

某学长讲课时提到可以不打LCT用KDT水过。然后自己too young直接上了KDT,显然没法保证复杂度就T了。然后看了看学长的博客发现要通过合并节点,打标记删除等操作保证复杂度。
代码丑,没写替罪羊重构。

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
#define N 100000
#define ts 320
#define inf 1e9
inline char tc(void){
    static char fl[10000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,10000,stdin),A==B)?EOF:*A++;
}
inline int read(void){
    int a=0,f=1;char c;
    while((c=tc())<'0'||c>'9')c=='-'?f=-1:0;
    while(c>='0'&&c<='9')a=a*10+c-'0',c=tc();
    return a*f;
}
int n,D,f[N+5],root,s,cnt,git,x_1,x_2,y_1,y_2,mx[N+5],mix[N+5],sz,d0[N+5],d1[N+5];
struct tree{
    int d[2],L,R,l,r,s;bool exist;
    inline bool operator<(const tree&x)const{
        return d[D]<x.d[D];
    }
}a[N+5],w[N+5];
inline void up(int k,int s){
    a[k].L=min(a[k].L,a[s].L),
    a[k].R=max(a[k].R,a[s].R);
}
inline void upw(int k,int s){
    w[k].L=min(w[k].L,w[s].L),
    w[k].R=max(w[k].R,w[s].R);
}
void insert(int k){
    int s=root;D=0;
    if(!s){root=k;return ;}
    while(1){
        up(s,k);
        if(a[k].d[D]<=a[s].d[D]){if(!a[s].l){a[s].l=k;break;}s=a[s].l;}
        else{if(!a[s].r){a[s].r=k;break;}s=a[s].r;}
        D^=1;
    }
}
void dfs(int k){
    if(a[k].exist)w[++sz]=a[k];
    if(a[k].l)dfs(a[k].l);
    if(a[k].r)dfs(a[k].r);
}
int rebuild(int l,int r,int d){
    int mid=l+r>>1;D=d;
    nth_element(w+l,w+mid,w+r+1),
    w[mid].L=w[mid].d[0],
    w[mid].R=w[mid].d[1];
    if(l<mid)w[mid].l=rebuild(l,mid-1,d^1);
    else w[mid].l=0;
    if(r>mid)w[mid].r=rebuild(mid+1,r,d^1);
    else w[mid].r=0;
    if(w[mid].l)upw(mid,w[mid].l);
    if(w[mid].r)upw(mid,w[mid].r);
    return mid;
}
void rebuild(){
    sz=0,dfs(root),root=rebuild(1,sz,0);
    for(int i=1;i<=sz;++i)a[i]=w[i];
}
int gf(int x){
    return x==f[x]?x:f[x]=gf(f[x]);
}
bool ok(int s){
    return a[s].d[0]>x_1&&a[s].d[0]<x_2&&a[s].d[1]>y_1&&a[s].d[1]<y_2;
}
bool pd(int s){
    int l=a[s].L,r=a[s].R;
    if(x_1<=l)return l<=x_2&&r>=y_1;
    else return x_1<=r&&y_2>=l;
}
void query(int s){
    if(a[s].exist&&ok(s)){
        a[s].exist=0;
        int x=gf(a[s].s),y=git;
        f[x]=y,mx[y]=max(mx[y],mx[x]),mix[y]=min(mix[y],mix[x]);
    }
    if(a[s].l&&pd(a[s].l))query(a[s].l);
    if(a[s].r&&pd(a[s].r))query(a[s].r);
}
int main(void){
    register int i,x,y,p,q,l,r;
    n=read();
    while(n--){
        s=read();
        switch(s){
            case 1:
                git=++cnt;
                d0[cnt]=x=read(),
                d1[cnt]=y=read(),
                f[cnt]=cnt,mix[cnt]=x,mx[cnt]=y,
                x_1=-inf,x_2=x,y_1=x,y_2=y;
                if(root)query(root);
                x_1=x,x_2=y,y_1=y,y_2=inf;
                if(root)query(root);
                x_1=-inf,x_2=x,y_1=y,y_2=inf;
                if(root)query(root);
                a[cnt].d[0]=a[cnt].L=mix[cnt],
                a[cnt].d[1]=a[cnt].R=mx[cnt],
                a[cnt].s=cnt,
                a[cnt].exist=1,insert(cnt);
                if(cnt%ts==0)rebuild();
            break;
            case 2:
                x=read(),y=read();
                if(gf(x)==gf(y)){puts("YES");break;}
                else{
                    y=f[y];
                    if(d1[x]<=mx[y]&&d0[x]>=mix[y]){
                        puts("YES");break;
                    }
                }
                puts("NO");
            break;
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值