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

关于线段树优化建图

时间:2024-07-20 12:07:13浏览次数:6  
标签:rt rson int 线段 add 建图 优化 节点 dis

线段树优化建图

引入

对于这道板子 但是我不会

大概意思就是:

有 \(n\) 个点、\(q\) 次操作。每一种操作为以下三种类型中的一种:

  1. 连一条 \(u→v\) 的有向边,权值为 w

  2. 对于所有 \(i∈[l,r]\) 连一条 \(u→i\) 的有向边,权值为 \(w\)

  3. 对于所有 \(i∈[l,r]\) 连一条 \(i→u\) 的有向边,权值为 \(w\)

求从点 \(s\) 到其他点的最短路。

\(1≤n,q≤10^5,1≤w≤10^9\)

——————————————华丽的分割线————————————

暴力 \(n^2\) 建边显然会爆时间,考虑优化。

考虑线段树优化建图。

线段树优化建图就是利用线段树,减少连边数量,从而降低复杂度。

过程

先种一颗线段树,并将所有叶子节点标号。
对于操作二,假设我们假设要假设...将 \(8\) 号节点向区间 \([3,7]\) 的所有点连权值为 \(w\) 的有向边

显然,可以向 \([3,4]\) 和 \([5,6]\) 的父亲节点分别连一条边,向 \(7\) 号节点连一条边,这样原本需要连 \(5\) 条边就被优化为连 \(3\) 条边。

于是 \(O(n)\) 便优化为 \(O(\log n)\)。

那么对于操作三也可以用以上方法连边。

对于同时进行操作二和三,我们考虑建两颗线段树,一个只连自上而下(根节点到子节点)的边,我们称为出树;另一个只连自下而上(子节点到根节点)的边,成为入树

由于两棵树相同位置的叶子节点原本就是一个节点,所以要在它们相互之间连边权为 \(0\) 的边。

这样我们的树就建好了呢~

建树
void build(int rt,int l,int r){
	if(l==r){
		a[l]=rt;//记录编号 
		return;
	}
	int mid=(l+r)>>1;
	add(rt,lson,0),add(rt,rson,0);//出树,根节点连子节点 
	add(lson+K,rt+K,0),add(rson+K,rt+K,0);//入树,子节点连根节点 
	build(lson,l,mid);
	build(rson,mid+1,r);
}

//主函数中
    build(1,1,n);
	for(int i=1;i<=n;i++){
		add(a[i],a[i]+K,0),add(a[i]+K,a[i],0);//两颗树之间原本相同的点连边
	}

这里 \(K\) 是个常数(根据数据范围而定),酱紫像我们这些懒人就不用写两个建树代码了也可以用两个函数分别实现入树和出树的构建。

接下来就是连边了,用操作二举例就是酱紫

连边
void modify(int rt,int l,int r,int ql,int qr,int v,int w){
	if(l>=ql&&r<=qr){
		if(op==2) add(v+K,rt,w);//入树的叶节点到出树的对应区间
		else add(rt+K,v,w);//入树的对应区间到出树的叶节点
		return;
	}
	int mid=(l+r)>>1;
	if(ql<=mid) modify(lson,l,mid,ql,qr,v,w);
	if(qr>mid) modify(rson,mid+1,r,ql,qr,v,w);
}

主函数中:
    for(int i=1;i<=Q;i++){
		cin>>op;
		if(op==1){
			cin>>v>>u>>w;
			add(a[v]+K,a[u],w);//操作一就是将入树的叶子节点和出树的叶子节点连边
		}else{
			cin>>v>>l>>r>>w;
			modify(1,1,n,l,r,a[v],w);
		}
	}

图建好啦~剩下的就是跑最短路

CODE

Elaina's Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define mkp make_pair
const int N=4e6+100;
const int inf=1e11;
const int K=1e6;

int hd[N],idx;
struct EDGE{
	int nxt,to,w;
}e[N];

void add(int x,int y,int z){
	e[++idx]={hd[x],y,z},hd[x]=idx;
}

int n,s,Q,dis[N],a[N];
bool vis[N];
priority_queue<pair<int,int> > q;

void dij(int x){
	memset(dis,0x3f,sizeof(dis));
	dis[x]=0;
	q.push(mkp(0,x));
	while(!q.empty()){
		int k=q.top().second;
		q.pop();
		if(vis[k]) continue;
		vis[k]=1;
		for(int i=hd[k];i;i=e[i].nxt){
			int to=e[i].to;
			if(dis[to]>dis[k]+e[i].w){
				dis[to]=dis[k]+e[i].w;
				q.push(mkp(-dis[to],to));
			}
		}
	}
}

#define lson (rt<<1)
#define rson (rt<<1|1)

void build(int rt,int l,int r){
	if(l==r){
		a[l]=rt;
		return;
	}
	int mid=(l+r)>>1;
	add(rt,lson,0),add(rt,rson,0);
	add(lson+K,rt+K,0),add(rson+K,rt+K,0); 
	build(lson,l,mid);
	build(rson,mid+1,r);
}

int op;
void modify(int rt,int l,int r,int ql,int qr,int v,int w){
	if(l>=ql&&r<=qr){
		if(op==2) add(v+K,rt,w);
		else add(rt+K,v,w);
		return;
	}
	int mid=(l+r)>>1;
	if(ql<=mid) modify(lson,l,mid,ql,qr,v,w);
	if(qr>mid) modify(rson,mid+1,r,ql,qr,v,w);
}

signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);

	cin>>n>>Q>>s;
	build(1,1,n);
	for(int i=1;i<=n;i++){
		add(a[i],a[i]+K,0),add(a[i]+K,a[i],0);
	}
	
	int v,u,w,l,r;
	for(int i=1;i<=Q;i++){
		cin>>op;
		if(op==1){
			cin>>v>>u>>w;
			add(a[v]+K,a[u],w);
		}else{
			cin>>v>>l>>r>>w;
			modify(1,1,n,l,r,a[v],w);
		}
	}
	dij(a[s]+K);
	for(int i=1;i<=n;i++){
		cout<<(dis[a[i]]==0x3f3f3f3f3f3f3f3fll?-1:dis[a[i]])<<' ';
	}
	return 0;
}

图自网搜,侵删。

标签:rt,rson,int,线段,add,建图,优化,节点,dis
From: https://www.cnblogs.com/Elaina-0/p/18312928

相关文章

  • 智能优化算法之蝙蝠算法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中有效管理线程池,以及如何通过优化并发性能提升应用的效率。线程池是管理线程的一个重要工具,能够提高系统的并发处理能力,并减少线程创建和销毁的......
  • 101文章解读与程序——中国电机工程学报EI\CSCD\北大核心《考虑气电联合需求响应的
    ......