Codeforces 786B Legacy 线段树优化建图

题意翻译
Rick 和他的同事们做出了一种新的带放射性的婴儿食品(???根据图片和原文的确如此…),与此同时很多坏人正追赶着他们。因此 Rick 想在坏人们捉到他之前把他的遗产留给 Morty。

在宇宙中一共有 nn 个星球标号为 1 \sim n1∼n。Rick 现在身处于标号为 ss 的星球(地球)但是他不知道 Morty 在哪里。

众所周知,Rick 有一个传送枪,他用这把枪可以制造出一个从他所在的星球通往其他星球(也包括自己所在的星球)的单行道路。但是由于他还在用免费版,因此这把枪的使用是有限制的。

默认情况下他不能用这把枪开启任何传送门。在网络上有 qq 个售卖这些传送枪的使用方案。每一次你想要实施这个方案时你都可以购买它,但是每次购买后只能使用一次。每个方案的购买次数都是无限的。

网络上一共有三种方案可供购买:

开启一扇从星球 vv 到星球 uu 的传送门;
开启一扇从星球 vv 到标号在 [l,r][l,r] 区间范围内任何一个星球的传送门。(即这扇传送门可以从一个星球出发通往多个星球)
开启一扇从标号在 [l,r][l,r] 区间范围内任何一个星球到星球 vv 的传送门。(即这扇传送门可以从多个星球出发到达同一个星球)
Rick 并不知道 Morty 在哪儿,但是 Unity 将要通知他 Morty 的具***置,并且他想要赶快找到通往所有星球的道路各一条并立刻出发。因此对于每一个星球(包括地球本身)他想要知道从地球到那个星球所需的最小钱数。

输入数据:
输入数据的第一行包括三个整数 nn,qq 和 ss 分别表示星球的数目,可供购买的方案数目以及地球的标号。

接下来的 qq 行表示 qq 种方案。

输入 1 v u w 表示第一种方案,其中 v,uv,u 意思同上,ww 表示此方案价格。
输入 2 v l r w 表示第二种方案,其中 v,l,rv,l,r 意思同上,ww 表示此方案价格。
输入 3 v l r w 表示第三种方案,其中 v,l,rv,l,r 意思同上,ww 表示此方案价格。

输出格式:
输出一行用空格隔开的 nn 个整数分别表示从地球到第 ii 个星球所需的最小钱数。

说明: 在第一组测试样例里,Rick 可以先购买第 44 个方案再购买第 22 个方案从而到达标号为 22 的星球.

【数据范围】
对于 100%100% 的数据,1\le n,q \le 10^51≤n,q≤10
5
,1\le w \le 10^91≤w≤10
9

输入输出样例
输入 #1复制

3 5 1
2 3 2 3 17
2 3 2 2 16
2 2 2 3 3
3 3 1 1 12
1 3 3 17
输出 #1复制
0 28 12

输入 #2复制
4 3 1
3 4 1 3 12
2 2 3 4 10
1 2 4 16
输出 #2复制
0 -1 -1 12


什么是线段树优化建图呢?

当有一个点到一个区间,或者一个区间到点这种操作,因为我们不能暴力去连边,所以我们可以利用线段树来优化建图的过程,因为线段树对应了所有区间,但是节点数不多,故我们可以这样优化。

对于这道题,既有点到区间,又有区间到点,所以我们需要两颗线段树。

然后线段树用动态开点最好,因为我们有两颗树。

大概图形:


AC代码:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10,M=2e6+10;
const int inf=0x3f3f3f3f3f3f3f3f;
int n,m,s,lc[N*20],rc[N*20],rt1,rt2,cnt,d[N<<2],vis[N<<2];
int head[N<<2],nex[M],to[M],w[M],tot;
inline void add(int a,int b,int c){
	to[++tot]=b; nex[tot]=head[a]; w[tot]=c; head[a]=tot;
}
void build1(int &p,int l,int r){
	if(l==r)	return void(p=l);
	p=++cnt; int mid=l+r>>1;
	build1(lc[p],l,mid); build1(rc[p],mid+1,r);
	add(p,lc[p],0); add(p,rc[p],0);
}
void build2(int &p,int l,int r){
	if(l==r)	return void(p=l);
	p=++cnt; int mid=l+r>>1;
	build2(lc[p],l,mid); build2(rc[p],mid+1,r);
	add(lc[p],p,0); add(rc[p],p,0);
}
void link1(int p,int l,int r,int ql,int qr,int u,int w){
	if(l==ql&&r==qr) return void(add(u,p,w));
	int mid=l+r>>1;
	if(qr<=mid)	link1(lc[p],l,mid,ql,qr,u,w);
	else if(ql>mid)	link1(rc[p],mid+1,r,ql,qr,u,w);
	else	link1(lc[p],l,mid,ql,mid,u,w),link1(rc[p],mid+1,r,mid+1,qr,u,w);
}
void link2(int p,int l,int r,int ql,int qr,int u,int w){
	if(l==ql&&r==qr) return void(add(p,u,w));
	int mid=l+r>>1;
	if(qr<=mid)	link2(lc[p],l,mid,ql,qr,u,w);
	else if(ql>mid)	link2(rc[p],mid+1,r,ql,qr,u,w);
	else	link2(lc[p],l,mid,ql,mid,u,w),link2(rc[p],mid+1,r,mid+1,qr,u,w);
}

void dijkstra(int s){
	priority_queue<pair<int,int> > q;
	memset(d,0x3f,sizeof d); d[s]=0;	q.push({0,s});
	while(q.size()){
		int u=q.top().second; q.pop();
		if(vis[u])	continue;	vis[u]=1;
		for(int i=head[u];i;i=nex[i]){
			if(!vis[to[i]]&&d[to[i]]>d[u]+w[i]){
				d[to[i]]=d[u]+w[i];	q.push({-d[to[i]],to[i]});
			}
		}
	}
}
signed main(){
	cin>>n>>m>>s; cnt=n;
	build1(rt1,1,n); build2(rt2,1,n);
	while(m--){
		int op,v,u,w,l,r; scanf("%lld",&op);
		if(op==1)	scanf("%lld %lld %lld",&v,&u,&w),add(v,u,w);
		else if(op==2){
			scanf("%lld %lld %lld %lld",&v,&l,&r,&w); 
			link1(rt1,1,n,l,r,v,w);
		}else{
			scanf("%lld %lld %lld %lld",&v,&l,&r,&w); 
			link2(rt2,1,n,l,r,v,w);
		}
	}
	dijkstra(s);
	for(int i=1;i<=n;i++)	printf("%lld ",d[i]==inf?-1:d[i]);puts("");
	return 0;
}
全部评论

相关推荐

评论
点赞
收藏
分享
牛客网
牛客企业服务