C131【模板】线段树分治+并查集 P5787 线段树分治

视频链接:C131【模板】线段树分治+并查集 P5787 线段树分治_哔哩哔哩_bilibili

 

 

 

 

D24 二分图判定 染色法 - 董晓 - 博客园 (cnblogs.com)

C124 扩展域并查集 P2024 [NOI2001] 食物链 - 董晓 - 博客园 (cnblogs.com)

P5787 二分图 /【模板】线段树分治 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

复制代码
// 线段树分治 O(mlognlogk)
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

#define pii pair<int,int>
#define ls (u<<1)
#define rs (u<<1|1)
#define mid ((l+r)>>1)
const int N=400005;
int n,m,k,p[N],high[N],top;
struct node{
  int x,y,hy;
}st[N];            //
vector<pii> tr[N]; //节点
bool ans[N];

int find(int x){ //查找根
  while(x!=p[x]) x=p[x];
  return p[x];
}
void merge(int x,int y){ //合并集合
  x=find(x),y=find(y);
  if(high[x]>high[y]) swap(x,y);
  st[++top]={x,y,high[y]};
  p[x]=y;
  high[y]+=(high[x]==high[y]); //相等则高度+1
}

void insert(int u,int l,int r,int L,int R,pii e){
  if(L>r||R<l) return;
  if(L<=l&&r<=R) return tr[u].push_back(e);
  insert(ls,l,mid,L,R,e);
  insert(rs,mid+1,r,L,R,e);
}
void solve(int u,int l,int r){
  int flag=0; //0没有奇环
  int now=top;
  for(auto e:tr[u]){
    merge(e.first, e.second+n);
    merge(e.second, e.first+n);
    if(find(e.first)==find(e.second)){
      flag=1; break; //有奇环则中断
    }
  }

  if(!flag){
    if(l==r) ans[l]=1; //是二分图
    else solve(ls,l,mid),solve(rs,mid+1,r);
  }

  while(top>now){ //撤销合并
    node t=st[top--];
    p[t.x]=t.x;
    high[t.y]=t.hy;
  }
}
int main(){
  scanf("%d%d%d",&n,&m,&k);
  for(int i=1;i<=2*n;i++) p[i]=i;
  for(int i=1,x,y,l,r;i<=m;i++){
    scanf("%d%d%d%d",&x,&y,&l,&r);
    insert(1,1,k,l+1,r,{x,y}); //插入时间线
  }
  solve(1,1,k);
  for(int i=1;i<=k;i++)puts(ans[i]?"Yes":"No");
}
复制代码

 

雷同题:

CF19E Fairy - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

复制代码
// 线段树分治 O(nlognlogn)
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

#define ls (u<<1)
#define rs (u<<1|1)
#define mid ((l+r)>>1)
#define pii pair<int,int>
const int N=10005;
int n,m,top;
int p[N<<1],siz[N<<1]; //并查集
struct node{
  int x,y;
}st[N<<1]; //

int find(int x){ //查找根
  return p[x]==x?x:find(p[x]);
}
void merge(int x,int y){ //合并集合
  x=find(x),y=find(y);
  if(x==y) return;
  if(siz[x]>siz[y])swap(x,y);
  st[++top]={x,y};
  p[x]=y;
  siz[y]+=siz[x];
}

vector<pii> tr[N<<2]; //节点
vector<int> ans;

void insert(int u,int l,int r,int L,int R,pii e){
  if(L>r||R<l) return;
  if(L<=l&&r<=R)return tr[u].push_back(e);
  insert(ls,l,mid,L,R,e);
  insert(rs,mid+1,r,L,R,e);
}
void solve(int u,int l,int r){
  int flag=0; //0没有奇环
  int now=top;
  for(auto e:tr[u]){
    merge(e.first, e.second+n);
    merge(e.second, e.first+n);
    if(find(e.first)==find(e.second)){
      flag=1; break; //有奇环则中断
    }
  }
  
  if(!flag){
    if(l==r) ans.push_back(l); //是二分图
    else solve(ls,l,mid),solve(rs,mid+1,r);
  }
  
  while(top>now){ //撤销合并
    node t=st[top--];
    p[t.x]=t.x;
    siz[t.y]-=siz[t.x];
  }
}
int main(){
  scanf("%d%d",&n,&m);
  if(m==0){puts("0");exit(0);}
  for(int i=1;i<=n<<1;i++) p[i]=i,siz[i]=1;
  
  for(int i=1,x,y;i<=m;i++){
    scanf("%d%d",&x,&y);
    if(i>1) insert(1,1,m,1,i-1,{x,y});
    if(i<m) insert(1,1,m,i+1,m,{x,y});
  }
  solve(1,1,m);
  printf("%d\n",ans.size());
  for(int i=0;i<ans.size();i++)printf("%d ",ans[i]);
}
复制代码

 

posted @   董晓  阅读(394)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示