首页 > 其他分享 >C131【模板】线段树分治 P5787 线段树分治

C131【模板】线段树分治 P5787 线段树分治

时间:2024-05-30 21:25:39浏览次数:20  
标签:C131 int 线段 分治 st high top

视频链接:

 

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

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

#define mid ((l+r)>>1)
const int N=400005;
int n,m,k,p[N],high[N],top;
struct E{int x,y;}e[N]; //存边
struct stack{
  int x,y,add;    //高度相等则add=1,否则add=0
}st[N];           //用栈记录边的端点的合并信息
vector<int> t[N]; //在线段树节点上记录时间线

void insert(int u,int l,int r,int L,int R,int i){
  if(L>r||R<l) return;
  if(L<=l&&r<=R){
    t[u].push_back(i); //节点[l,r]上记录第i条时间线
    return;
  }
  insert(u<<1,l,mid,L,R,i);
  insert(u<<1|1,mid+1,r,L,R,i);
}
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[x]==high[y]}; //合并前的信息
  p[x]=y; //x指向y
  if(high[x]==high[y]) high[y]++; //y的高度+1
}
void solve(int u,int l,int r){ //线段树分治
  int flag=1; //1是二分图,0不是二分图
  int lasttop=top;
  //如果当前区间有时间线,若无环则合并,有环则输出
  for(int i=0;i<t[u].size();i++){
    if(find(e[t[u][i]].x)==find(e[t[u][i]].y)){
      for(int k=l;k<=r;k++) puts("No");
      flag=0; break;
    }
    merge(e[t[u][i]].x, e[t[u][i]].y+n);
    merge(e[t[u][i]].y, e[t[u][i]].x+n);
  }
  //如果当前区间存在二分图,则继续分治,直到叶子
  if(flag){
    if(l==r) puts("Yes"); //r时刻是二分图
    else{
      solve(u<<1,l,mid);
      solve(u<<1|1,mid+1,r); //继续分治
    }
  }
  //回溯,如果当前区间做过合并操作,则逐个撤销
  while(top>lasttop){ 
    high[p[st[top].x]]-=st[top].add;
    p[st[top].x]=st[top].x;
    top--;
  }
}
int main(){
  scanf("%d%d%d",&n,&m,&k);
  for(int i=1;i<=2*n;i++) p[i]=i,high[i]=1;
  for(int i=1,l,r;i<=m;i++){
    scanf("%d%d%d%d",&e[i].x,&e[i].y,&l,&r);
    insert(1,1,k,l+1,r,i); //插入时间线
  }
  solve(1,1,k); //线段树分治
}

 

标签:C131,int,线段,分治,st,high,top
From: https://www.cnblogs.com/dx123/p/18213260

相关文章

  • [SDCPC2023] Colorful Segments 线段树转移DP
    Codeforces链接​  洛谷题目链接#[SDCPC2023]ColorfulSegments##题面翻译**【题目描述】**考虑数轴上的$n$条线段,其中第$i$条线段的左端点为$l_i$,右端点为$r_i$。每一条线段都被涂上了颜色,其中第$i$条线段的颜色为$c_i$($0\lec_i\le1$)。颜色共有两种,$c_i......
  • 简单分治
    《算法设计与分析》期末复习最大连续子序列设\(f(l,r)\)为\(a_l,...,a_r\)的最大连续子序列的和取$mid=\frac{l+r}{2}$,当最大连续子序列在任意一边时,有$f(l,r)=max{f(l,mid),f(mid+1,r}}当最大连续子序列跨越了\(mid\),需要额外的用$\Theta(n)$的时......
  • 线段树分裂 学习笔记
    过程线段树分裂是线段树合并的逆操作,即将一个区间信息分裂到新的树中,新的树一般需要新建。注意当分裂和合并都存在时,我们在合并的时候必须回收节点,以避免分裂时会可能出现节点重复占用的问题。时间复杂度显然\(\mathcal{O}(\logn)\)。实现//将x分裂出[p,q]到now上v......
  • 线段树合并 学习笔记
    过程合并并不困难,对于两棵线段树,合并无疑就是就两棵线段树维护的区间信息进行合并。就比如,有两棵线段树如下图:将第二棵树合并到第一棵树,就是把除了维护\([2,2]\)的全部对应加,而\([2,2]\)则新开节点维护。时间复杂度显然\(\mathcal{O}(n\logn)\)。实现intMerge(i......
  • 线段树结构体模板
    线段树是一种维护区间和等功能的数据结构structSegTree{ structnode{ intl,r,sum,len,laz; }tree[N<<2]; inlinevoidpushdown(intu){ intlson=u<<1,rson=lson|1; tree[lson].laz+=tree[u].laz; tree[rson].laz+=tree[u].laz; tree[lson].sum+=tree[lson].len......
  • 线段树维护区间字符的两道例题(CF240F CF558E)
    CF240F:https://www.luogu.com.cn/problem/CF240F题目大意:给定一个长为n的由a到z组成的字符串,有m次操作,每次操作将[l,r]的字符串进行重排,得到字典序最小的字符串,输出m次操作后的字符串。大致思路:1.首先我们要想区间内的字典序最小的回文串要怎么构造。回文串无非就两种类型:有一......
  • 【知识点】浅入线段树与区间最值问题
    前言:这又是一篇关于数据结构的文章。今天来讲一下线段树和线段树的基本应用。线段树(SegmentTree),是一种非常高效且高级的数据结构,其主要用于区间查询和与区间更新相关的问题,例如进行多次查询区间最大值、最小值、更新区间等操作。区间最值问题引入常见的线段树题型就是区......
  • 线段树
    线段树线段树,一种拿来解决\(RMQ\)与区间和问题的高效的数据结构,对于这两种问题,线段树均能在\(O(mlog_{2}n)\)的时间复杂度内解决。在这两个基础的应用场景的基础上,线段树还发展出了各种丰富的应用。总的来说,线段树是一个应用广泛,功能强大的数据结构,本章将介绍其概念及基本操......
  • 线段树
    P3372【模板】线段树1#include<bits/stdc++.h>usingnamespacestd;#defineintlonglong#defineendl"\n"#definelcp<<1////p*2#definercp<<1|1////p*2+1constintN=100005;typedefstructnode{intl,r,sum,ta......
  • 判断点在形状里,点在线段上
    /************************************************************************函数名: OnSegment功能描述: 判断点q是否在p1和p2的线段上(调试用)输入参数: p1线段端点1;p2线段端点2;q要判断的点;输出参数: 无返回值: ture点在线段上;false点不在线段上******......