题目
https://cn.vjudge.net/problem/CodeForces-786B
题意
最短路
思路
建两棵树 入树和出树 入树每个结点向孩子建边 出树向父亲建边 每棵树的叶子结点不能相互到达 只能通过新建的边到达 即最短路
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define par pair<ll,ll>
#define rep(i,a,b) for(int i = (a);i <= (b);i++)
const ll inf = 1e16;
const int maxn = 100010;
int n,m,s,cnt;
struct node
{
int v,nxt;
ll dis;
}e[maxn<<5];
int head[maxn*10],tot;
ll d[maxn*10];
int in[maxn<<2],out[maxn<<2],vis[maxn*10];
void add(int u,int v,ll dis) //建边
{
e[++tot].nxt = head[u];
e[tot].v = v;
e[tot].dis = dis;
head[u] = tot;
}
void build(int s,int t,int p)// 建正反两颗树
{
if(s==t)
{
in[p] = out[p] = s;
return ;
}
int mid = s + t>> 1;
in[p] = ++cnt;
out[p] = ++cnt;
build(s,mid,p<<1);
build(mid+1,t,p<<1|1);
add(in[p],in[p<<1],0);
add(in[p],in[p<<1|1],0);
add(out[p<<1],out[p],0);
add(out[p<<1|1],out[p],0);
}
void qvet(int u,int l,int r,int s,int t,int p,ll dis,ll tt) //加边
{
if(l <= s&&t <= r)
{
if(tt==2) add(u,in[p],dis);
else if(tt == 3) add(out[p],u,dis);
return ;
}
int mid = (s + t) >> 1;
if(l <= mid) qvet(u,l,r,s,mid,p<<1,dis,tt);
if(r > mid) qvet(u,l,r,mid+1,t,p<<1|1,dis,tt);
}
void dij()
{
for(int i = 1;i <= cnt;i++)
d[i] = inf;
d[s] = 0;
priority_queue<pair<ll,ll> > q;
q.push(make_pair(0,s));
while(!q.empty())
{
int u = q.top().second;
q.pop();
if(vis[u]) continue;
vis[u] = 1;
for(int i = head[u];i;i = e[i].nxt)
{
int v = e[i].v;
if(d[v] > d[u]+e[i].dis)
{
d[v] = d[u] + e[i].dis;
q.push(make_pair(-d[v],v));
}
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&s);
cnt = n;
build(1,n,1);
for(int i = 1;i <= m;i++)
{
int k,u;
scanf("%d%d",&k,&u);
if(k == 1)
{
int v;
ll dis;
scanf("%d%lld",&v,&dis);
add(u,v,dis);
}
else
{
int l,r;
ll dis;
scanf("%d%d%lld",&l,&r,&dis);
qvet(u,l,r,1,n,1,dis,k);
}
}
dij();
for(int i = 1;i <= n;i++)
if(d[i] == inf) printf("-1 ");
else printf("%lld ",d[i]);
return 0;
}