视频链接:
Communication Towers - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
// 线段树分治 O(mlognlogn) #include <iostream> #include <cstring> #include <algorithm> #include <vector> using namespace std; #define int long long #define ls (u<<1) #define rs (u<<1|1) #define mid ((l+r)>>1) #define N 200005 int n,m,a[N],b[N]; int p[N],high[N],tag[N],top; vector<pair<int,int> >tr[N<<2]; //记录时间区间上出现的边 struct node{ int x,y,hy; }st[N<<1]; //用栈记录边的端点的合并信息 void insert(int u,int l,int r,int L,int R,int x,int y){ if(L>r||R<l) return; if(L<=l&&r<=R){ tr[u].push_back({x,y}); //当前节点(时间区间)出现的边 return; } insert(ls,l,mid,L,R,x,y); insert(rs,mid+1,r,L,R,x,y); } int find(int x){ //查找根 if(p[x]==x) return x; return find(p[x]); } void merge(int x,int y){ //合并集合 x=find(x),y=find(y); if(x==y) return; if(high[x]>high[y]) swap(x,y); st[++top]={x,y,high[y]}; //记录合并信息 p[x]=y; //x指向y high[y]+=(high[x]==high[y]); tag[x]-=tag[y]; //消除y上已有标记的影响 } void solve(int u,int l,int r){ int now=top; for(int i=0;i<tr[u].size();i++) merge(tr[u][i].first,tr[u][i].second); if(l==r)tag[find(1)]++; //r时刻根上打标记 else solve(ls,l,mid),solve(rs,mid+1,r); while(top>now){ //撤销合并 node s=st[top--]; p[s.x]=s.x; high[s.y]=s.hy; tag[s.x]+=tag[s.y]; //下传标记 } } signed main(){ cin>>n>>m; int k=2e5; for(int i=1;i<=n;i++)p[i]=i; for(int i=1;i<=n;i++)scanf("%lld%lld",&a[i],&b[i]); for(int i=1;i<=m;i++){ int x,y;scanf("%lld%lld",&x,&y); int l=max(a[x],a[y]),r=min(b[x],b[y]); if(l<=r) insert(1,1,k,l,r,x,y); //出现时间有交集则插入 } solve(1,1,k); //线段树分治 for(int i=1;i<=n;i++) if(tag[i])printf("%lld ",i); return 0; }
标签:CF1814F,C132,Towers,top,high,int,tag,include From: https://www.cnblogs.com/dx123/p/18224146