题意
给定
n
n
n个点,现在有
3
3
3种连边操作。
第一种,点
u
u
u向点
v
v
v连一条长度为
w
w
w的边。
第二种,点
u
u
u向
[
l
,
r
]
[l,r]
[l,r]区间内的所有点连一条长度为
w
w
w的边。
第三种,
[
l
,
r
]
[l,r]
[l,r]区间内的所有点向点
u
u
u连一条长度为
w
w
w的边。
现在给定
q
q
q个操作,问这些操作过后,起点到其他点最短距离为多少。
数据范围
1
≤
n
,
q
≤
100000
1 \leq n,q \leq 100000
1≤n,q≤100000
1
≤
v
,
u
,
l
,
r
≤
n
1 \leq v,u,l,r \leq n
1≤v,u,l,r≤n
1
≤
w
≤
1
0
9
1 \leq w \leq 10^9
1≤w≤109
思路
我们注意到数据范围,边数可能会非常多,内存不够用,所以不能用常规方法建图。这里引入一个技术,线段树优化建图。
我们考虑第二种操作,点
u
u
u向
[
l
,
r
]
[l,r]
[l,r]区间内的所有点连一条长度为
w
w
w的边。我们可以建一棵线段树,根节点连向左右儿子节点,权重为
0
0
0。
再考虑第三种操作,
[
l
,
r
]
[l,r]
[l,r]区间内的所有点向点
u
u
u连一条长度为
w
w
w的边。我们可以建一棵线段树,左右儿子节点连向根节点,权重为
0
0
0。
然后,我们再将两棵线段树的叶子节点连起来,权重为
0
0
0(其实这里两棵线段树的叶子节点可以认为是公用的)。
建好线段树后,我们再考虑如何加边。对于第一种操作,两点直接加边即可。对于第二种操作,我们就将
u
u
u点连向第一棵线段树的相应区间,因为本来
u
u
u是要连向区间内的所有点,现在只用连对应的区间,然后再根据第一棵线段树的性质,发现相当于连到了区间内所有点;对于第三种操作,我们就将第二棵线段树的对应区间连向
u
u
u点,原因同理。这样图就建好了。
最后再从起点开始跑一遍Dijkstra算法,本题就做完了。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long ll;
typedef pair<ll,int> pli;
const int N = 100010;
const ll inf = 1e18;
int n,m,s;
int h[N<<3], e[N*20], ne[N*20], idx;
ll w[N*20];
int tot, root[2];
ll dist[N<<3];
bool st[N<<3];
struct Node
{
int ls, rs;
}tr[N<<3];
void add(int a,int b,ll c)
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
}
void build1(int &k,int l,int r)
{
if(l==r){
k = l;
return;
}
k = ++tot;
int mid = l + r >> 1;
build1(tr[k].ls,l,mid), build1(tr[k].rs,mid+1,r);
add(k,tr[k].ls,0), add(k,tr[k].rs,0);
}
void build2(int &k,int l,int r)
{
if(l==r){
k = l;
return;
}
k = ++tot;
int mid = l + r >> 1;
build2(tr[k].ls,l,mid), build2(tr[k].rs,mid+1,r);
add(tr[k].ls,k,0), add(tr[k].rs,k,0);
}
void modify1(int k,int l,int r,int ql,int qr,int u,ll w)
{
if(l>=ql&&r<=qr){
add(u,k,w);
return;
}
int mid = l + r >> 1;
if(ql<=mid) modify1(tr[k].ls,l,mid,ql,qr,u,w);
if(qr>mid) modify1(tr[k].rs,mid+1,r,ql,qr,u,w);
}
void modify2(int k,int l,int r,int ql,int qr,int u,ll w)
{
if(l>=ql&&r<=qr){
add(k,u,w);
return;
}
int mid = l + r >> 1;
if(ql<=mid) modify2(tr[k].ls,l,mid,ql,qr,u,w);
if(qr>mid) modify2(tr[k].rs,mid+1,r,ql,qr,u,w);
}
void dijkstra()
{
memset(dist,0x3f,sizeof(dist));
dist[s] = 0;
priority_queue<pli,vector<pli>,greater<pli> > heap;
heap.push({0,s});
while(heap.size()){
auto t = heap.top();
heap.pop();
int ver = t.second;
ll distance = t.first;
if(st[ver]) continue;
st[ver] = true;
for(int i=h[ver];~i;i=ne[i]){
int j = e[i];
if(dist[j]>distance+w[i]){
dist[j] = distance + w[i];
heap.push({dist[j],j});
}
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&s);
tot = n;
memset(h,-1,sizeof(h));
build1(root[0],1,n), build2(root[1],1,n);
for(int i=1;i<=m;i++){
int op;
scanf("%d",&op);
if(op==1){
int u,v;
ll w;
scanf("%d%d%lld",&u,&v,&w);
add(u,v,w);
}
else{
int u,l,r;
ll w;
scanf("%d%d%d%lld",&u,&l,&r,&w);
if(op==2) modify1(root[0],1,n,l,r,u,w);
else modify2(root[1],1,n,l,r,u,w);
}
}
dijkstra();
for(int i=1;i<=n;i++){
if(dist[i]>inf) printf("-1 ");
else printf("%lld ",dist[i]);
}
printf("\n");
return 0;
}