Title
有 n n n个点,然后有 m m m次操作,其中有 3 3 3种建图的操作,最后询问的以 s s s为起点,分别以每个点为终点的最短路。
- 正常连接 x x x和 y y y
- 连接 x x x到 [ l , r ] [l,r] [l,r]
- 连接 [ 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;
}