bzoj 5005: 乒乓游戏

题意

题面:www.lydsy.com/JudgeOnline/upload/task.pdf

题解

感觉不是特别难的一个题
思路想出来了,但是没有用到区间长度是递增的
所以时间复杂度不对啊。。
考虑到区间长度是递增的,所以其实我们对于之前的点
如果他有一个端点在某一个区间里面,那么他们就是可以互相到达的
这个的话用并查集缩点就可以了
然后线段树优化一下
不想多说了。。具体代码

CODE:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int MAX=(1<<30);
const int N=100005*2;
int n;
int A[N];//所有存在的数 
struct qq
{
    int l,r,op;
}s[N];
struct qr
{
    int l,r;
    int s1,s2;
    vector<int> c;
}tr[N*2];int num=0;
void LSH ()
{
    sort(A+1,A+1+A[0]);
    int ooo=1;
    for (int u=2;u<=A[0];u++)
        if (A[u]!=A[ooo])
            A[++ooo]=A[u];
    for (int u=1;u<=n;u++)
    {
        if (s[u].op==2) continue;
        int l=1,r=ooo;
        while (l<=r)
        {
            int mid=(l+r)>>1;
            if (s[u].l==A[mid]) {s[u].l=mid;break;}
            else if (s[u].l>A[mid]) l=mid+1;
            else r=mid-1;
        }
        l=1,r=ooo;
        while (l<=r)
        {
            int mid=(l+r)>>1;
            if (s[u].r==A[mid]) {s[u].r=mid;break;}
            else if (s[u].r>A[mid]) l=mid+1;
            else r=mid-1;
        }
    }
}
void bt (int l,int r)
{
    int a=++num;
    tr[a].l=l;tr[a].r=r;
    if (l==r) return ;
    int mid=(l+r)>>1;
    tr[a].s1=num+1;bt(l,mid);
    tr[a].s2=num+1;bt(mid+1,r);
}
int tot,belong[N];
int L[N],R[N];
int f[N];
int find (int x){return f[x]==x?f[x]:f[x]=find(f[x]);}
void Del (int now,int x)
{
    if (tr[now].c.size())
    {
        for (int u=0;u<tr[now].c.size();u++)
        {
            int id=tr[now].c[u];
            f[find(id)]=tot;
            L[tot]=min(L[tot],L[id]);
            R[tot]=max(R[tot],R[id]);
        }
        tr[now].c.clear();
    }
    if (tr[now].l==tr[now].r) return ;
    int mid=(tr[now].l+tr[now].r)>>1;
    int s1=tr[now].s1,s2=tr[now].s2;
    if (x<=mid) Del(s1,x);
    else Del(s2,x);
}
void update (int now,int l,int r)
{
    if (l>r) return ;
    if (tr[now].l==l&&tr[now].r==r)
    {
        tr[now].c.push_back(tot);
        return ;
    }
    int mid=(tr[now].l+tr[now].r)>>1;
    int s1=tr[now].s1,s2=tr[now].s2;
    if (r<=mid) update(s1,l,r);
    else if (l>mid) update(s2,l,r);
    else update(s1,l,mid),update(s2,mid+1,r);
}
int main()
{
    scanf("%d",&n);
    for (int u=1;u<=n;u++)
    {
        scanf("%d%d%d",&s[u].op,&s[u].l,&s[u].r);
        if (s[u].op==1)
        {
            A[++A[0]]=s[u].l;A[++A[0]]=s[u].r;
        }
    }
    LSH();
    bt(1,A[0]);
    for (int u=1;u<=n;u++)
    {
        if (s[u].op==1)
        {
            tot++;
            L[tot]=s[u].l;
            R[tot]=s[u].r;
            f[tot]=tot;
            Del(1,s[u].l);
            Del(1,s[u].r);
            update(1,L[tot]+1,R[tot]-1);
        }
        else
        {
            int y=find(s[u].l),x=find(s[u].r);
            if (x==y||(L[x]<L[y]&&L[y]<R[x])||(L[x]<R[y]&&R[y]<R[x]))
                printf("YES\n");
            else printf("NO\n");
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值