链接: D. Legacy
题意:
一眼看上去是求最短路,但他给出的边权是,一个点到一个区间的边权(也就是说 u 到 【l,r】内的点都有一条边)。
思路:
因为区间内的点都是连续的,所以我们可以用线段树把这些连续的点缩成几个区间,把区间变成一个新的点,再让这个新点于原来的点之间连上权值为 0 的边,这样可以很大的降低复杂度。
这个巨巨写得很详细 D. Legacy
代码:
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn = 4e6 + 7;
int head[maxn],num,n,q,s,id1[maxn],id2[maxn],ma=0,vis[maxn];
ll dis[maxn];
struct node{
int to,next,w;
}e[maxn];
void add(int u,int v,int w){
e[num].next=head[u];
e[num].to=v;
e[num].w=w;
head[u]=num++;
}
priority_queue<pair<ll, ll> > que ;
void dij(int s){
for(int i = 0; i <= 2*ma; i++){
dis[i]=1e18;
}
memset(vis,0,sizeof(vis));
dis[s]=0;
que.push(make_pair(0,s));
while(que.size())
{
int u=que.top().second;que.pop();
if(vis[u]) continue;
vis[u]=1;
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
ll w=e[i].w;
if(dis[v]>dis[u]+w)
{
dis[v]=dis[u]+w;
que.push(make_pair(-dis[v],v));
}
}
}
}
void build1(int l,int r,int rt){
if(l == r){
id1[l] = rt ;
ma=max(ma,rt);
return ;
}
int mid = (l + r) / 2;
add(rt,rt<<1,0);
add(rt,rt<<1|1,0);
build1(l,mid,rt<<1);
build1(mid+1,r,rt<<1|1);
}
void build2(int l,int r,int rt){
if(l == r){
id2[l] = rt+ma;
return ;
}
int mid = (l + r) / 2;
add((rt<<1)+ma,rt+ma,0);
add((rt<<1|1)+ma,rt+ma,0);
build2(l,mid,rt<<1);
build2(mid+1,r,rt<<1|1);
}
void update1(int L,int R,int idd,int w,int l,int r,int rt){
if(L <= l && R >= r){
add(idd,rt,w);
return ;
}
int mid=(l+r)/2;
if(L <= mid) update1(L,R,idd,w,l,mid,rt<<1);
if(R > mid) update1(L,R,idd,w,mid+1,r,rt<<1|1);
}
void update2(int L,int R,int idd,int w,int l,int r,int rt){
if(L <= l && R >= r){
add(rt+ma,idd,w);
return ;
}
int mid=(l+r)/2;
if(L <= mid) update2(L,R,idd,w,l,mid,rt<<1);
if(R > mid) update2(L,R,idd,w,mid+1,r,rt<<1|1);
}
int main(){
scanf("%d%d%d",&n,&q,&s);
memset(head,-1,sizeof(head));
build1(1,n,1);
build2(n+1,2*n,1);
int op,w,v,u,l,r;
while(q--){
scanf("%d",&op);
if(op==1){
scanf("%d%d%d",&v,&u,&w);
add(id2[v + n],id1[u],w);
}
if(op==2){
scanf("%d%d%d%d",&v,&l,&r,&w);
update1(l,r,id2[v+n],w,1,n,1);
}
if(op==3){
scanf("%d%d%d%d",&v,&l,&r,&w);
update2(l+n,r+n,id1[v],w,n+1,2*n,1);
}
}
for(int i = 1; i <= n; i++){
add(id1[i],id2[i+n],0);
add(id2[i+n],id1[i],0);
}
dij(id2[s+n]);
for(int i = 1; i <= n; i++){
if(dis[id1[i]]>=1e18) printf ("-1 ");
else printf ("%lld ",dis[id1[i]]);
}
printf ("\n");
}