#线段树优化建图# [luogu CF786B] Legacy

Title

CF786B Legacy

n n n个点,然后有 m m m次操作,其中有 3 3 3种建图的操作,最后询问的以 s s s为起点,分别以每个点为终点的最短路。

  1. 正常连接 x x x y y y
  2. 连接 x x x [ l , r ] [l,r] [l,r]
  3. 连接 [ l , r ] [l,r] [l,r] x x x

Solution

注意dijkstra中判断vis,因为我也不知道我到底改了些什么东西,最后把vis的位置换了一下就AC了

跟这一道题#线段树优化建图# [luogu P4083] [USACO17DEC]A Pie for a Pie G
的区别:对于第二和第三个操作,要分别建两个线段树,一个从下往上(第二个操作就相当于从另一个线段树的叶子节点向这棵线段树的区间连边),另一个从上往下,叶子节点可以共用。


Code

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<string>
#define ll long long 
#define mp(x,y) make_pair((x),(y))
#define rep(i,x,y) for(ll i=x;i<=y;i++)
using namespace std; 
const ll N=1e6+5,INF=0x3f3f3f3f3f3f3f3f; 
struct node{
	ll y,z,next; 
}a[N*4];
ll n,Q,S; 
ll lson[N*4],rson[N*4],T1,T2,tot,head[N],cnt,f[N]; 
priority_queue<pair<ll,ll> >q;
bool vis[N*4]; 
ll read(){
	ll p=0; char c=getchar(); 
	while (!isdigit(c)) c=getchar(); 
	while (isdigit(c)) p=(p<<3)+(p<<1)+c-48,c=getchar(); 
	return p; 
}
void add(ll x,ll y,ll z){
	a[++tot]=(node){y,z,head[x]}; head[x]=tot; 
}
void build(ll &p,ll l,ll r,ll k){
	if (l==r){ p=l; return;}
	p=++cnt; 
	ll mid=(l+r)>>1; 
	build(lson[p],l,mid,k); 
	build(rson[p],mid+1,r,k); 
	if (k==0) add(lson[p],p,0),add(rson[p],p,0); 
	else add(p,lson[p],0),add(p,rson[p],0); 
}
void update(ll p,ll l,ll r,ll L,ll R,ll k,ll w,ll OUT){
	if (L<=l&&R>=r){ OUT?add(p,k,w):add(k,p,w); return;}
	ll mid=(l+r)>>1; 
	if (L<=mid) update(lson[p],l,mid,L,R,k,w,OUT); 
	if (R>mid) update(rson[p],mid+1,r,L,R,k,w,OUT); 
}
void dijkstra(){
	memset(f,0x3f,sizeof(f)); 
	memset(vis,0,sizeof(vis)); 
	q.push(mp(0,S)); f[S]=0; 
	while (q.size()){
		ll x=q.top().second; q.pop(); 
		if (vis[x]) continue; vis[x]=1;
		for(ll i=head[x];i;i=a[i].next){
			ll y=a[i].y; 
			if (f[y]>f[x]+a[i].z){
				f[y]=f[x]+a[i].z;  
				q.push(mp(-f[y],y));
			}
		}
	}
}
int main(){	
	n=read(),Q=read(),S=read(); cnt=n; 
	build(T1,1,n,0); 
	build(T2,1,n,1); 
	while(Q--){
		ll z=read(),x=read(); 
		if (z==1){
			ll y=read(),w=read(); 
			add(x,y,w); 
		} else {
			ll l=read(),r=read(),w=read(); 
			update((z==2)?T2:T1,1,n,l,r,x,w,z-2); 
		}
	}
	dijkstra(); 
	rep(i,1,n) printf("%lld ",(f[i]==INF)?-1:f[i]); 
	return 0; 
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值