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

Legacy(线段树优化建图)

时间:2024-07-19 21:44:34浏览次数:7  
标签:rt 连边 int 线段 建图 Legacy 区间 dis

CF786B-Legacy

线段树优化建图板子题。。。。。。

暴力建边 \(\mathcal O(n^2)\)) 肯定会\(TLE\)

但仔细分析可以发现,题面中有一个我们非常熟悉的字眼“区间”,这启示我们,可不可以以此作为解题的突破口呢?

答案是肯定的。想到区间我们可以联想到各种我们很熟悉的\(trick\),如前缀和、差分、线段树等。

但对于此题而言前缀和、差分似乎都不太行,于是我们考虑线段树,利用“每一个区间都可以表示为线段树上 \(\log n\) 个区间“来减少边的个数。

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

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

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

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

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

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

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

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

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

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

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

图建好了,剩下来就是dijkstra板子:

个人认为码风良好
#include<bits/stdc++.h>
#define lcs (rt<<1)
#define rcs (rt<<1|1)
using namespace std;
const int maxn=114514;
struct tree{
	int up,down,l,r;
}tree[maxn<<3];
int n,q,s,m,cnt,tot;long long dis[maxn*17];bool vis[maxn*17];
int h[maxn*17],nxt[maxn*19],to[maxn*19],w[maxn*19];
void add(int x,int y,int z){
	tot++;
	nxt[tot]=h[x];
	to[tot]=y;
	w[tot]=z;
	h[x]=tot;
}
void pushup(int rt){
	add(tree[lcs].up,tree[rt].up,0);
	add(tree[rcs].up,tree[rt].up,0);
}
void pushdown(int rt){
	add(tree[rt].down,tree[lcs].down,0);
	add(tree[rt].down,tree[rcs].down,0);
}
void build(int rt,int l,int r){
	tree[rt].l=l,tree[rt].r=r;
	tree[rt].up=++cnt,tree[rt].down=++cnt;
	if(l==r){
		add(tree[rt].down,l,0);
		add(l,tree[rt].up,0);
		return;
	}
	int mid=(l+r)>>1;
	build(lcs,l,mid),build(rcs,mid+1,r);
	pushup(rt),pushdown(rt);
}
void update(int rt,int l,int r,int id,int w,bool flag){
	if(l>tree[rt].r||r<tree[rt].l) return;
	if(l<=tree[rt].l&&tree[rt].r<=r){
		if(flag) add(tree[rt].up,id,w);
		else add(id,tree[rt].down,w);
		return;
	}
	update(lcs,l,r,id,w,flag),update(rcs,l,r,id,w,flag);
}
void dj(int st){
	priority_queue< pair<double,int> > q;
	memset(dis,0x3f,sizeof dis);
	dis[st]=0;q.push(make_pair(0,st));
	while(!q.empty()){
		int x=q.top().second;
		q.pop();
		vis[x]=true;
		for(int i=h[x];i;i=nxt[i]){
			int y=to[i];
			if(dis[y]>dis[x]+w[i]){
				dis[y]=dis[x]+w[i];
				if(!vis[y]) q.push(make_pair(-dis[y],y));
			}
		}
	}
}
int main(){
	scanf("%d%d%d",&n,&q,&s);
	cnt=n;build(1,1,n);
	for(int i=1,tp,v,u,l,r,w;i<=q;i++){
		scanf("%d",&tp);
		if(tp==1){
			scanf("%d%d%d",&v,&u,&w);
			if(v==u) continue;
			add(v,u,w);
		}
		if(tp==2){
			scanf("%d%d%d%d",&v,&l,&r,&w);
			update(1,l,r,v,w,0);
		}
		if(tp==3){
			scanf("%d%d%d%d",&u,&l,&r,&w);
			update(1,l,r,u,w,1);
		}
	}
	dj(s);
	for(int i=1;i<=n;i++) printf("%lld ",dis[i]==0x3f3f3f3f3f3f3f3f?-1:dis[i]);
	return 0;
}

除了代码,其它都不是我写的

主要是觉得写题解直接放代码不太好

(转载自洛谷@tzc_wk

标签:rt,连边,int,线段,建图,Legacy,区间,dis
From: https://www.cnblogs.com/hypixel/p/18312423

相关文章

  • 线段树优化建图
    线段树优化建图用途:处理区间连边做法:建两颗线段树,一颗处理区间的入边,另一颗处理出边(如果用一颗线段树的话,边权就都为0了)例题:Legacy板子题,直接看代码点此查看代码#include<bits/stdc++.h>#include<bits/extc++.h>//usingnamespace__gnu_pbds;//usingnamespa......
  • P3373 【模板】线段树 2(区间乘+加操作,先乘后加原则)
    题目来源:https://www.luogu.com.cn/problem/P3373//题意:对区间[l,r]可以乘法,加法操作,查询和操作。//思路:既有乘法又有加法,肯定是要有两个标记。纯加法和纯乘法操作是很简单的,但是既有乘法又有加法涉及到先乘后加和先加后乘的顺序。//////所以现在是如何将先加后成也可以......
  • 【数据结构】- 线段树
    前言线段树用于维护区间上的值,可以在$O(\logn)$的时间复杂度内实现单点,区间修改及查询。并且所有满足结合律的运算都可以用线段树进行加速。基本操作建树给你长度为$n$的正整数序列$A$,要你实现单点修改与区间查询。(加和)这就是线段树的基本题目。线段树,字面上来看就是把......
  • 基础线段树相关
    权值线段树线段树在这里作为前置知识,我们就不说了,而且权值线段树也不是核心内容,不会大篇幅讲。首先,权值线段树在维护什么?维护的是桶。然后,权值线段树有什么用?可以求一些序列的第\(k\)大之类的问题。于是我们放个板子题。第k小整数简单题,直接看代码和注释就行,当然也可以......
  • 2021 ICPC 网络赛 第二场 L Euler Function(势能线段树,欧拉函数,状态压缩)
    2021ICPC网络赛第二场LEulerFunction题意给定序列,定义两个操作\(l,r,x\)对区间\([l,r]\)的数乘\(x\)\(l,r\)求\(\sum\phi{a}_{i}\)思路注意欧拉函数的性质,若\(i\bmodp=0\),\(\phi(i*p)=p*\phi(i)\),否则\(\phi(i*p)=(p-1)*\phi(i)\)因为\(x,w\)的......
  • 使用预训练模型(yolov8、MobileNetV2、ResNet50)与Gradio构建图像目标检测Web应用
    简介:  利用gradio设计一个web运用,实现图片主体物的识别。  1)用户可以通过网页提交一张图片。  2)web应用将输出这张图片中主体物的名称(中英文都可以)。  3)可以使用预训练的模型。利用预训练实现对物体识别准备工作在开始之前,请确保你的环境中已安装了以下依赖......
  • 李超线段树
    李超线段树用来维护线段(一次函数)信息。值域线段树:对于值域线段树维护\(x\)轴上的区间\([l,r]\),维护\(s\),表示在\(x=mid\)处可能取最大值的线段(不一定就是最大)。添加操作:新边\(u\),旧边\(v\)。1.将边拆为最多\(\log\)个在线段树上的线段。2.如果\(u\)与\(v\)存在完全覆盖关......
  • 建图的一些技巧
    已经不止一次了解到建图的技巧了,例如:最大流建立超级源点,超级汇点建反图,但已经忘了这个题是什么时候的题了点权转成边权2024/7/15介绍点权转边权如下所示,建立一个有\(2N\)个顶点和\(N+M\)条边(成本只分配给边)的有向图,答案就是从顶点\(1_\text{in}\)到顶点\(i_\te......
  • 吉司机线段树
    吉司机线段树为了方便说板子,这里直接把板子题放上去讲了。线段树3简单说一下\(5\)个操作都在干什么:区间加一个数。区间和一个数取最小值。区间求和。区间求最大值。区间求历史最大值。好了,前\(4\)个操作如果单独拉出来出成一道题,显然是好做的,于是我们的......
  • 线段树——AcWing 245. 你能回答这些问题吗
    目录线段树定义运用情况注意事项解题思路AcWing245.你能回答这些问题吗题目描述运行代码代码思路改进思路线段树定义线段树是一种用于区间查询和更新问题的数据结构。它通过递归地将一个区间分解为若干子区间,每个节点代表一个子区间的和、最小值、最大值等信息,......