首页 > 其他分享 >浅谈线段树分治

浅谈线段树分治

时间:2024-11-15 13:19:16浏览次数:1  
标签:dsu 浅谈 int 线段 分治 top define

大体思想

线段树分治是一种用于解决区间操作和时间点查询的算法。它的主要思想是以时间为下标建立线段树,将在某一时间段内生效的操作记录在线段树上,然后对于某一时间点的查询,可以直接从线段树上得到结果。线段树是一种容易维护区间的数据结构,它通过不断以中点分治区间,形成了 \(log\) 层的树形结构。————————————————————————————————————baidu

类似一边分治,同时还代表线段树。

具体用法

在时间段中搞事情

搞什么?

将时间段加入线段树中。

在区间查询中搞事情

搞什么?

搞很多事情。

例题

二分图 /【模板】线段树分治

考虑直接将时间加入线段树,但是这里的线段树需要用vector来存当前区间内不会消失的边,再来判断二分图

我们知道二分图的性质就是不存在奇环,但是直接使用平凡的 01染色 肯定就 TLE 了,考虑可撤销并查集(不能用普通并查集是因为在回溯的时候存在需要撤销之前的操作)维护,如果发现一条边在未加入前,其两点在并查集中在一个集合,那么就存在奇环(这个很显然吧)。

#include <bits/stdc++.h>
using namespace std;
#define il inline
#define pb(x) push_back(x)
#define pii pair<int,int>
#define fi first
#define se second
#define mp make_pair
const int N=2e5+5;
int n,m,k;
struct node
{
	int u,v;
}e[N];
stack<pii>s;
namespace dsu //并查集
{

int fa[N],h[N];

il void init(){for(int i=1;i<=n*2;i++)fa[i]=i,h[i]=0;}

il int getf(int x)
{
	if(x==fa[x])return x;
	return fa[x]=getf(fa[x]);
}

il void merge(int u,int v)
{
	u=getf(u),v=getf(v);
	if(u==v)return;
	if(h[u]>h[v])swap(u,v);
	s.push(mp(u,h[u]==h[v]?1:0));
	fa[u]=v;
	h[v]+=(h[u]==h[v]?1:0);
}

}
namespace tr //线段树
{
	
#define ls (p<<1)
#define rs ((p<<1)|1)
#define mid ((l+r)>>1)
vector<int>t[N<<2];

il void upd(int p,int l,int r,int L,int R,int id)
{
	if(r<L||R<l)return;
	if(L<=l&&r<=R){t[p].pb(id);return;}
	upd(ls,l,mid,L,R,id);upd(rs,mid+1,r,L,R,id);
}

il void solve(int p,int l,int r)
{
	int flag=1,now=s.size();
	for(int x:t[p])
	{
		int fu=dsu::getf(e[x].u),fv=dsu::getf(e[x].v);
		if(fu==fv)
		{
			for(int i=l;i<=r;i++)cout<<"No\n";
			flag=0;
			break;
		}
		dsu::merge(e[x].u+n,e[x].v);
		dsu::merge(e[x].u,e[x].v+n);
	}
	if(flag)
	{
		if(l==r)cout<<"Yes\n";
		else{solve(ls,l,mid);solve(rs,mid+1,r);}
	}
	while(s.size()>now)
	{
		dsu::h[dsu::fa[s.top().fi]]-=s.top().se;
		dsu::fa[s.top().fi]=s.top().fi;
		s.pop();
	}
}

}
int main()
{
	cin>>n>>m>>k;
	for(int i=1,l,r;i<=m;i++)
	{
		cin>>e[i].u>>e[i].v>>l>>r;
		if(l^r)tr::upd(1,1,k,l+1,r,i);
	}
	dsu::init();
	tr::solve(1,1,k);
	return 0;
}

标签:dsu,浅谈,int,线段,分治,top,define
From: https://www.cnblogs.com/tyccyt/p/18547784

相关文章

  • 笔记-CDQ 分治
    CDQ分治分治,分而治之,一般采取递归的形式,先将要处理的部分分开分别处理,再合并计算。而CDQ分治正是基于分治思想的离线算法。具体地,CDQ分治对询问进行分治,对于一个询问区间\([l,r]\),CDQ分治进行以下操作:处理\([l,mid]\)。处理\([mid+1,r]\)。计算\([l,mid]\)中的修......
  • .NET Core 反射底层原理浅谈
    简介反射,反射,程序员的快乐。前期绑定与后期绑定在.NET中,前期绑定(EarlyBinding)是指在编译时就确定了对象的类型和方法,而后期绑定(LateBinding)或动态绑定是在运行时确定对象的类型和方法。前置知识:C#类型系统结构C#作为C++++,在类型系统上沿用C++的类型系统前期绑定在代......
  • zkw 线段树-原理及其扩展
    前言许多算法的本质是统计。线段树用于统计,是沟通原数组与前缀和的桥梁。《统计的力量》清华大学-张昆玮关于线段树前置知识:线段树OIWiki。线段树是一种专门维护区间问题的数据结构。线段树对信息进行二进制化处理并在树形结构上维护,以此让处理速度达到\(O(\log{n})\)......
  • #5. 可持久化线段树
    请先学习线段树的相关内容喵。线段树博客待填可持久化线段树0x01.简介OIWiki上的神秘定义:函数式线段树是指使用函数式编程思想的线段树。在函数式编程思想中,将计算机运算视为数学函数,并避免可改变的状态或变量。不难发现,函数式线段树是完全可持久化的。可持久化线段树......
  • 线段树
    线段树题目:https://www.acwing.com/problem/content/1277//*题目:https://www.acwing.com/problem/content/1277/给定一个正整数数列a1,a2,…,an,每一个数都在0∼p−1之间。可以对这列数进行两种操作:添加操作:向序列后添加一个数,序列长度变成n+1;询问......
  • .NET Core 泛型底层原理浅谈
    .NETCore泛型底层原理浅谈 简介泛型参考资料烂大街,基本资料不再赘述,比如泛型接口/委托/方法的使用,逆变与协变。泛型好处有如下几点代码重用算法重用,只需要预先定义好算法,排序,搜索,交换,比较等。任何类型都可以用同一套逻辑类型安全编译器保证不会将int传给string简单清......
  • P8868 [NOIP2022] 比赛(线段树维护区间历史和)
    题意给定排列\(a,b\),\(q\)次询问\(l,r\),你需要求出\(\sum_{l\lel'\ler'\ler}(\max_{i=l'}^{r'}a_i)(\max_{i=l'}^{r'}b_i)\)对\(2^{64}\)取模的值。\(n,q\le2.5\times10^5\)分析根据经典套路,按\(r\)扫描线,维护两个单调栈,那么加入一个数就相当于进行若干段区......
  • .NET Core 委托底层原理浅谈
    简介.NET通过委托来提供回调函数机制,与C/C++不同的是,委托确保回调是类型安全,且允许多播委托。并支持调用静态/实例方法。简单来说,C++的函数指针有如下功能限制,委托作为C#中的上位替代,能弥补函数指针的不足。类型不安全函数指针可以指向一个方法定义完全不同的函数。在编译期......
  • 浅谈贪心算法
    浅谈贪心算法贪心算法,指在问题求解时,每一步都做出“当前看起来最好的决策”。它没有固定的算法模板,灵活性强。在OI领域,无论是入门组,还是省选,NOI,或多或少都出过贪心题。可见贪心的重要性之大。使用贪心算法解决问题,必须满足“无后效性”。满足“无后效性”不一定当前的决策......
  • 学习日历day02 分治法-归并排序(递归版)
    归并排序快速排序类似于二叉树前序遍历(根节点、左子节点、右子节点)归并排序类似于二叉树后序遍历(左子节点、右子节点、根节点)归并排序的递归实现归并排序:持续分割区间,直到剩下最后一个节点,在归并排序的过程中,数组的分割可以看作是在构建一棵二叉树。具体来说,每次分割都将当......