高手训练 线段树T3 P1753:区间连通性

线段树/标记永久化

复杂度 \(O(nlogn)\)

题解有误,并非所有与线段树节点[l,r]相交的所有区间[s.t]都要存入vector

插入区间[s,t]时,我们覆盖了一段完整的区间,如图

实质上是覆盖了表面的一层,即标记不下传

故我们merge时要考虑每一层的vector

插入时,如果两个区间恰好相接,也视作互相到达,所以合并时用(s,t)合并,插入时用[s+1,t-1]插入

由于区间按长度从小到大插入,故不存在这样的情况:

故merge的区间一定是两两可达的,用并查集来维护这种关系

最后,若区间存在包含关系,则A可以到达B,B不能到达A(一端端点重合也算),则特判即可,由于端点可能重合,故不能只判断一个端点

代码非常简单:

#include<bits/stdc++.h>
using namespace std;

#define go(i,a,b) for(int i=a;i<=b;++i)
#define com(i,a,b) for(int i=a;i>=b;--i)
#define mem(a,b) memset(a,b,sizeof(a))
#define ls rt<<1
#define rs rt<<1|1

const int inf=0x3f3f3f3f,N=2e5+10;

int n,m,op[N],a[N],b[N],c[N],d[N],f[N],rk[N],id,tot;
vector<int>inter[N<<2];

void read(int &x){
    x=0;char c=getchar(),f=1;
    while(!isdigit(c)){ if(c=='-') f=-1; c=getchar(); }
    while(isdigit(c)){ x=x*10+c-'0'; c=getchar(); }
    x*=f;
}
inline int find(int x){ return f[x]=f[x]==x?x:find(f[x]); }

void merge(int rt,int l,int r,int k){
    for(int i=0;i<inter[rt].size();++i){
        int x=inter[rt][i];
        x=find(x);
        f[x]=id;
        c[id]=min(c[id],c[x]);
        d[id]=max(d[id],d[x]);
    }
    inter[rt].clear();
    if(l==r) return;
    int mid=l+r>>1;
    if(k<=mid) merge(ls,l,mid,k);
    else merge(rs,mid+1,r,k);
}

void insert(int rt,int l,int r,int x,int y,int k){
    if(l>=x&&r<=y){
        inter[rt].push_back(k);
        return; 
    }
    int mid=l+r>>1;
    if(x<=mid) insert(ls,l,mid,x,y,k);
    if(y>mid) insert(rs,mid+1,r,x,y,k);
}

int main(){
    //freopen("input.txt","r",stdin);
    read(n);
    go(i,1,n){
        read(op[i]),read(a[i]),read(b[i]);
        if(op[i]==1) rk[++tot]=a[i],rk[++tot]=b[i];
    }
    sort(rk+1,rk+tot+1);
    tot=unique(rk+1,rk+tot+1)-rk-1;
    go(i,1,n) if(op[i]==1){
        a[i]=lower_bound(rk+1,rk+tot+1,a[i])-rk;
        b[i]=lower_bound(rk+1,rk+tot+1,b[i])-rk;
    }
    int x,y;
    go(i,1,n){
        if(op[i]==1){
            f[++id]=id,c[id]=a[i],d[id]=b[i];
            merge(1,1,tot,a[i]);
            merge(1,1,tot,b[i]);
            insert(1,1,tot,c[id]+1,d[id]-1,f[id]);
        }
        else{
            x=find(a[i]),y=find(b[i]);
            if(x==y) puts("YES");
            else{
                if(c[x]>c[y]&&c[x]<d[y]||d[x]>c[y]&&d[x]<d[y]) puts("YES");
                else puts("NO");
            }
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/White-star/p/11583828.html