昨天晚上本来想认真打一场的,,结果陪女朋友去了。。
回来之后看了看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"); }