线段树优化建图(知识总结+板子整理)

思路来源

https://www.cnblogs.com/Miracevin/p/9863080.html

知识点整理

原博主的图片,出树和入树 和 本代码里的tin和tout正好相反……

两棵树,一棵tin树,一棵tout树,

让tin[k]中的父亲向儿子连边,代表u向区间连边,

让tout[k]中的儿子向父亲连边,代表区间向点u连边,

让入树和出树的叶子结点指向相同的真实节点

点u向区间[l,r]连边,只需add(u,tin[k],w),由于tin[k]下放到儿子值为0,故u连区间[l,r]均为w

区间[l,r]向点u连边,只需add(tout[k],u,w),由于tout[k]对应的[l,r]区间到tout[k]的距离为0,则[l,r]到u的距离为w

板子

以atcoder NIKKEI Programming Contest 2019-2 D - Shortest Path on a Line为例

题意给n(n<=1e5)个点,以下m(m<=2e5)个操作,

第i次操作,给出li,ri,对[li,ri]内的任意两点s,t,令s和t之间连一条权值ci(1<=ci<=1e9)的无向边

求点1到点n的最短路

操作等价于区间[li,ri]连虚点(n+i)权值c,虚点(n+i)连区间[li,ri]权值0,

对共n+m个点建线段树优化建图之后,跑dijkstra即可

#include<bits/stdc++.h>
#define INF 0x7fffffff
const int N=200010;
using namespace std;
 
inline int read(){
	char ch=getchar();int x=0,f=1;
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
} 
//180W点 520W条边 n+m 20W 
struct edge{
	int v,nxt,w;
}e[N*40];
int head[N<<4],cnt;
long long inf;
int n,m,s;
 
void add(int u,int v,int w){
	e[++cnt].v=v;
	e[cnt].w=w;
	e[cnt].nxt=head[u];
	head[u]=cnt;
}
 
int tin[N<<4],tout[N<<4],temp;
long long dis[N<<4];
 
void build(int k,int l,int r){
	if(l==r){
		tin[k]=tout[k]=l;
		return ;
	}
	int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	tin[k]=++temp;tout[k]=++temp;
	add(tout[k<<1],tout[k],0);
	add(tout[k<<1|1],tout[k],0);
	add(tin[k],tin[k<<1],0);
	add(tin[k],tin[k<<1|1],0);
}
 
void update1(int k,int l,int r,int L,int R,int u,int w){
	if(L<=l&&r<=R){
		add(u,tin[k],w);
		return ;
	}
	int mid=(l+r)>>1;
	if(mid>=L){
		update1(k<<1,l,mid,L,R,u,w);
	}
	if(mid<R){
		update1(k<<1|1,mid+1,r,L,R,u,w);
	}
}
 
void update2(int k,int l,int r,int L,int R,int u,int w){
		if(L<=l&&r<=R){
		add(tout[k],u,w);
		return ;
	}
	int mid=(l+r)>>1;
	if(mid>=L){
		update2(k<<1,l,mid,L,R,u,w);
	}
	if(mid<R){
		update2(k<<1|1,mid+1,r,L,R,u,w);
	}
}
 
struct node{
	int u;
	long long d;
	bool operator<(const node&h)const{return d>h.d;};
};
 
void dij(){
	memset(dis,0x3f,sizeof(dis));
	inf=dis[1];
	priority_queue<node> q;
	dis[s]=0;
	q.push((node){s,0});
	while(!q.empty()){
		node now=q.top();
		int u=now.u;
		long long d=now.d;
		q.pop();
		if(d!=dis[u])continue;
		for(int i=head[u];i;i=e[i].nxt){
			int v=e[i].v,w=e[i].w;
			if(dis[v]>dis[u]+w){
				dis[v]=dis[u]+w;
				q.push((node){v,dis[v]});
			}
		}
	}
}
 
int main(){
	
	n=read(),m=read(),s=1;
	temp=n+m; 
	
	build(1,1,n+m);
	for(int i=1;i<=m;i++){
		int l=read(),r=read(),w=read();
		update1(1,1,n+m,l,r,n+i,0);
		update2(1,1,n+m,l,r,n+i,w);
	}
	dij(); 
	//cout<<inf<<endl;
	if(dis[n]!=inf){
		printf("%lld ",dis[n]);
	}
	else printf("-1 ");
	return 0;
}
发布了467 篇原创文章 · 获赞 53 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/Code92007/article/details/102992888