cf1278D——树的性质+并查集+线段树/DFS判环

昨天晚上本来想认真打一场的,,结果陪女朋友去了。。

回来之后看了看D,感觉有点思路,结果一直到现在才做出来

首先对所有线段按左端点排序,然后用并查集判所有边是否联通,即遍历每条边i,和前一条不覆盖它的边合并,和后一条不被它覆盖的边合并

再用线段树求边的总条数

ps.其实可以直接用并查集合并的思路,每个点往前往后连边,建图然后DFS判环/联通就可以了

#include<bits/stdc++.h>
#include<set>
using namespace std;
#define N 1000005

int n,dp[N];
pair<int,int>p[N];
set<int> s;
set<int>::iterator it; 

int F[N],pre[N],r[N];
int find(int x){
    return F[x]==x?x:F[x]=find(F[x]);
} 

#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int lazy[N<<2];
void pushdown(int rt){
    if(lazy[rt]){
        lazy[rt<<1]+=lazy[rt];
        lazy[rt<<1|1]+=lazy[rt];
        lazy[rt]=0;
    }
}
void update(int L,int R,int v,int l,int r,int rt){
    if(L<=l && R>=r){
        lazy[rt]+=v;
        return;
    }
    int m=l+r>>1;
    if(L<=m)update(L,R,v,lson);
    if(R>m)update(L,R,v,rson);
}
int query(int pos,int l,int r,int rt){
    if(l==r)return lazy[rt];
    pushdown(rt);
    int m=l+r>>1;
    if(pos<=m)return query(pos,lson);
    else return query(pos,rson);
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++)scanf("%d%d",&p[i].first,&p[i].second);
    sort(p+1,p+1+n);
    for(int i=1;i<=n;i++)r[p[i].second]=i; 
     
    s.clear();
    for(int i=1;i<=n;i++)F[i]=i;
    
    int tot=0;
    
    for(int i=1;i<=n;i++){
        it = s.lower_bound(p[i].second);
        if(i==1 || it==s.begin()){//没有前驱 
            dp[p[i].second]=-1;
            s.insert(p[i].second);
        }
        else {//有前驱 
            it--;
            dp[p[i].second]=*it;
            int tmp=dp[*it];
            if(p[i].first<=tmp){
                puts("NO");
                return 0;
            }
            s.insert(p[i].second);
            
            int fu=find(i),fv=find(r[*it]);
            if(fu!=fv && p[i].first<=*it)
                F[fu]=fv;
        }
        if(i<n){//找后继 
            int L=i+1,R=n,mid,ans=0;
            while(L<=R){
                mid=L+R>>1;
                if(p[mid].second>p[i].second)
                    ans=mid,R=mid-1;
                else L=mid+1;
            }
            if(ans){
                int fu=find(i),fv=find(ans);
                if(fu!=fv && p[i].second >= p[ans].first)
                    F[fu]=fv;
            }
        }
        tot+=query(p[i].first,1,1000000,1)-query(p[i].second,1,1000000,1);
        update(p[i].first,p[i].second,1,1,1000000,1);
    }
    
    if(tot!=n-1){puts("NO");return 0;}
    
    int cnt=0;
    for(int i=1;i<=n;i++)
        if(find(i)==i)cnt++;
    if(cnt==1)puts("YES");
    else puts("NO");
}
原文地址:https://www.cnblogs.com/zsben991126/p/12072687.html