首页 > 其他分享 >线段树优化建图

线段树优化建图

时间:2024-07-20 12:09:55浏览次数:6  
标签:rt 连边 int 线段 建图 op 优化 dis

为什么?

什么时候用线段树优化建图
例题

如果此时暴力建边 \(O(n^{2})\) 肯定会 TLE

观察到题目中的“区间”此时考虑用线段树优化建图,在每个区间上连边(线段树上只有 \(\log{n}\) 个区间)来减少边的个数

实现方法?

摘抄自 tzx_wk

我们就拿 \(2\) 操作来举例吧。现在假设假如有一个点要与 \([1,3]\) 的点连边权为 \(w\) 的边,那么我们建出线段树:

将 \([1,3]\) 拆成 \([1,2]\) 与 \([3,3]\) 然后分别连边,边权为 \(w\)(图中橙色的边):

但是仅仅只连这两条边是远远不够的,因为你只将这个点与一个区间表示的点连了边,并没有将其连到具体的单点上。

因此我们还从每个区间向其子区间连边,由于你向下走,从一个大区间对应到一个小区间没有代价,因此这些边的边权为 \(0\) 。

操作 \(3\) 也同理,只不过把之前连的所有边都反向。

以上是操作 \(2\) 与操作 \(3\) 分开来考虑的情形,那么操作 \(2\) 与操作 \(3\) 相结合该怎么办呢?

显然你不能把它们揉在一棵线段树上,因为你线段树上每条边向上向下边权都为 \(0\),故从原点到每个点的最短路也为 \(0\),这……还玩个什么啊。。。。。。

因此可以想到建两棵线段树,第一棵只连自上而下的边,第二棵只连自下而上的边:

对于 \(2\) 操作,你就从第二棵线段树的叶子节点向第一棵线段树中的对应区间连边(下图中橙色的边)。

对于 \(3\) 操作,你就从第二棵线段树中的对应区间向第一棵线段树中的叶子节点连边(下图中粉色的边)。

还有一点,就是两棵线段树的叶子节点实际上是同一个点,因此要在它们互相之间连边权为 \(0\) 的边(下图中黄色的边)

以上就是实现过程的思路。

代码?

1. 建树过程

  • 首先我们要建两颗树,如下,\(op=2\) 时建入树(从点向区间连边),\(op=3\) 时建出树(从区间向点连边)
  • 最底层的叶子节点编号为 \(1\) 到 \(n\) (这样就不用在两颗线段树的叶子节点间连边了),其它节点在建树时由 \(cnt\) (初值为 \(n\) )再为节点编号赋初值
  • 因为节点编号不满足 \(ls=rt<<1\), \(rs=rt<<1|1\),所以我们用 \(ls[rt]\) 和 \(rs[rt]\) 数组存儿子节点的编号
  • 别忘了在线段树内部的连边
#define l(x) tr[x].l
#define r(x) tr[x].r
struct node{
	int l,r;
}tr[maxn*4];
int cnt,rt1,rt2,ls[maxn*4],rs[maxn*4];
void build(int &rt,int l,int r,int op)
{
	if (l==r) {rt=l;l(rt)=r(rt)=l;return ;}
	rt=++cnt;l(rt)=l;r(rt)=r;int mid=(l+r)>>1;
	build(ls[rt],l,mid,op);build(rs[rt],mid+1,r,op);
	if (op==2) addedge(rt,ls[rt],0),addedge(rt,rs[rt],0);//入树,自上而下
	else addedge(ls[rt],rt,0),addedge(rs[rt],rt,0);//出树,自下而上
}

2.实现操作中的建边

我们用 \(update\) 每次递归连边实现就好,根据op的值实现操作 \(2\) 和 \(3\)

void update(int rt,int l,int r,int x,int z,int op)
{
	if (l<=l(rt)&&r(rt)<=r)
	{
	 	if (op==2) addedge(x,rt,z);
	 	else addedge(rt,x,z);
	 	return ;
	}
	int mid=(tr[rt].l+tr[rt].r)>>1;
	if (l<=mid) update(ls[rt],l,r,x,z,op);
	if (mid<r) update(rs[rt],l,r,x,z,op);
}

3.最短路

跑一遍正常的 \(dijkstra\) 就好

int n,q,s,dis[maxn*4];
bool vis[maxn*4];
struct point{
	int dis,id;
	bool operator < (const point &a) const{
		return dis>a.dis;
	}
};
void dij(int s)
{
	priority_queue<point>q;
	memset(dis,0x3f,sizeof(dis));
	dis[s]=0;q.push(point{0,s});
	while (!q.empty())
	{
		int x=q.top().id;q.pop();
		if (vis[x]) continue;
		vis[x]=1;
		for (int i=he[x];i;i=ne[i])
		  if (!vis[to[i]]&&dis[x]+w[i]<dis[to[i]])
		  {
		  	dis[to[i]]=dis[x]+w[i];
		  	q.push(point{dis[to[i]],to[i]});
		   } 
	}
}
完整代码
#include<bits/stdc++.h>
#define int long long
#define l(x) tr[x].l
#define r(x) tr[x].r
using namespace std;
const int maxn=1e5+10;
const int INF=4557430888798830399;
int read()
{
	int x=0,f=1;char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return x*f;
}
int tot,he[maxn*4],ne[maxn*20];
int to[maxn*20],w[maxn*20];
struct node{
	int l,r;
}tr[maxn*4];
void addedge(int u,int v,int z)
{
	ne[++tot]=he[u];
	he[u]=tot;
	to[tot]=v;
	w[tot]=z;
}
int cnt,rt1,rt2,ls[maxn*4],rs[maxn*4];
void build(int &rt,int l,int r,int op)
{
	if (l==r) {rt=l;l(rt)=r(rt)=l;return ;}
	rt=++cnt;l(rt)=l;r(rt)=r;int mid=(l+r)>>1;
	build(ls[rt],l,mid,op);build(rs[rt],mid+1,r,op);
	if (op==2) addedge(rt,ls[rt],0),addedge(rt,rs[rt],0);//入树,自上而下
	else addedge(ls[rt],rt,0),addedge(rs[rt],rt,0);//出树,自下而上
}
void update(int rt,int l,int r,int x,int z,int op)
{
	if (l<=l(rt)&&r(rt)<=r)
	{
	 	if (op==2) addedge(x,rt,z);
	 	else addedge(rt,x,z);
	 	return ;
	}
	int mid=(tr[rt].l+tr[rt].r)>>1;
	if (l<=mid) update(ls[rt],l,r,x,z,op);
	if (mid<r) update(rs[rt],l,r,x,z,op);
}
int n,q,s,dis[maxn*4];
bool vis[maxn*4];
struct point{
	int dis,id;
	bool operator < (const point &a) const{
		return dis>a.dis;
	}
};
void dij(int s)
{
	priority_queue<point>q;
	memset(dis,0x3f,sizeof(dis));
	dis[s]=0;q.push(point{0,s});
	while (!q.empty())
	{
		int x=q.top().id;q.pop();
		if (vis[x]) continue;
		vis[x]=1;
		for (int i=he[x];i;i=ne[i])
		  if (!vis[to[i]]&&dis[x]+w[i]<dis[to[i]])
		  {
		  	dis[to[i]]=dis[x]+w[i];
		  	q.push(point{dis[to[i]],to[i]});
		   } 
	}
}
signed main()
{
	n=read();q=read();s=read();
	cnt=n;build(rt1,1,n,2);build(rt2,1,n,3);
	for (int i=1,op,v,u,z,l,r;i<=q;i++)
	{
		op=read();
		if (op==1)
		{
			v=read();u=read();
			z=read();addedge(v,u,z);
		}
		else 
		{
			v=read();l=read();r=read();z=read();
			update(op==2?rt1:rt2,l,r,v,z,op);			
		}
	}
	dij(s);
	for (int i=1;i<=n;i++)
	  if (dis[i]==INF) printf("-1 ");
	  else printf("%lld ",dis[i]);
	return 0;
}

标签:rt,连边,int,线段,建图,op,优化,dis
From: https://www.cnblogs.com/zhagnxinyue/p/18312803

相关文章

  • 关于线段树优化建图
    线段树优化建图引入对于这道板子题但是我不会大概意思就是:有\(n\)个点、\(q\)次操作。每一种操作为以下三种类型中的一种:连一条\(u→v\)的有向边,权值为w对于所有\(i∈[l,r]\)连一条\(u→i\)的有向边,权值为\(w\)对于所有\(i∈[l,r]\)连一条\(i→u\)的......
  • 智能优化算法之蝙蝠算法BA
    优化算法是一类旨在寻找问题最优解的算法,通过迭代地调整候选解,以期找到最优或接近最优的解。优化问题在许多领域中普遍存在,如工程设计、经济规划、机器学习等。优化算法可以分为许多种类,如启发式算法、精确算法和元启发式算法等。蝙蝠优化算法的介绍蝙蝠优化算法(BatAlgo......
  • 智能优化算法之灰狼优化算法(GWO)
    智能优化算法是一类基于自然界中生物、物理或社会现象的优化技术。这些算法通过模拟自然界中的一些智能行为,如遗传学、蚁群觅食、粒子群体运动等,来解决复杂的优化问题。智能优化算法广泛应用于各种工程和科学领域,因其具有全局搜索能力、鲁棒性强以及易于实现等优点。灰狼优......
  • Legacy(线段树优化建图)
    CF786B-Legacy线段树优化建图板子题。。。。。。暴力建边\(\mathcalO(n^2)\))肯定会\(TLE\)但仔细分析可以发现,题面中有一个我们非常熟悉的字眼“区间”,这启示我们,可不可以以此作为解题的突破口呢?答案是肯定的。想到区间我们可以联想到各种我们很熟悉的\(trick\),如前缀和、......
  • 线段树优化建图
    线段树优化建图用途:处理区间连边做法:建两颗线段树,一颗处理区间的入边,另一颗处理出边(如果用一颗线段树的话,边权就都为0了)例题:Legacy板子题,直接看代码点此查看代码#include<bits/stdc++.h>#include<bits/extc++.h>//usingnamespace__gnu_pbds;//usingnamespa......
  • 聚类优化:Scikit-Learn中的数据标签分配艺术
    聚类优化:Scikit-Learn中的数据标签分配艺术在聚类分析中,标签分配是一个关键步骤,它直接影响聚类的解释性和实用性。Scikit-Learn(简称sklearn),作为Python中广受欢迎的机器学习库,提供了多种工具和方法来优化聚类标签的分配。本文将详细介绍这些方法,并提供详细的解释和代码示例......
  • mysql联合索引优化
    【MySQL】之联合索引与最左匹配原则王廷云的博客已于2023-12-1009:48:32修改阅读量2k收藏24点赞数28分类专栏:MySQL文章标签:mysql数据库版权MySQL专栏收录该内容27篇文章3订阅订阅专栏前言:最左匹配原则在我们MySQL开发过程中和面试过程中经常遇到,为了加深印象和......
  • 基于Java和MySQL的数据库优化技术
    基于Java和MySQL的数据库优化技术大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!今天我们将探讨如何基于Java和MySQL进行数据库优化,提升系统的性能和稳定性。我们将从查询优化、索引使用、事务管理以及连接池配置几个方面来介绍具体的优化技术。1.查询......
  • P3373 【模板】线段树 2(区间乘+加操作,先乘后加原则)
    题目来源:https://www.luogu.com.cn/problem/P3373//题意:对区间[l,r]可以乘法,加法操作,查询和操作。//思路:既有乘法又有加法,肯定是要有两个标记。纯加法和纯乘法操作是很简单的,但是既有乘法又有加法涉及到先乘后加和先加后乘的顺序。//////所以现在是如何将先加后成也可以......
  • Java中的线程池管理与并发性能优化
    Java中的线程池管理与并发性能优化大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!今天我们将探讨如何在Java中有效管理线程池,以及如何通过优化并发性能提升应用的效率。线程池是管理线程的一个重要工具,能够提高系统的并发处理能力,并减少线程创建和销毁的......