bzoj 3073: [Pa2011]Journeys

注意是无向图。线段树优化连边跑最短路。
   
   
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#define ll long long
#define inf 1e9
#define eps 1e-8
#define md
#define N 5000010
using namespace std;
struct yts { int t,ne; bool l;} e[13000010];
int pos1[500010],pos2[500010];
int v[N],dis[N];
int n,num,S,cnt;
bool vis[N];
struct QQ { int x,dis;};
struct cmp
{
bool operator () (QQ a,QQ b) { return a.dis>b.dis;}
};
priority_queue<QQ,vector<QQ>,cmp> q;
 
void put(int x,int y,int l)
{//printf("put %d %d %d\n",x,y,l);
num++; e[num].t=y; e[num].l=l;
e[num].ne=v[x]; v[x]=num;
}
 
void build1(int i,int l,int r)
{
if (l==r) { pos1[l]=i; return;}
int mid=(l+r)>>1;
build1(i<<1,l,mid); build1(i<<1|1,mid+1,r);
put(i<<1,i,0); put(i<<1|1,i,0);
}
 
void build2(int i,int l,int r)
{
if (l==r) { pos2[l]=i+4*n; return;}
int mid=(l+r)>>1;
build2(i<<1,l,mid); build2(i<<1|1,mid+1,r);
put(i+4*n,(i<<1)+4*n,0); put(i+4*n,(i<<1|1)+4*n,0);
}
 
void modify1(int i,int l,int r,int ql,int qr,int x)
{
if (ql<=l&&r<=qr) { put(i,x,0); return;}
int mid=(l+r)>>1;
if (ql<=mid) modify1(i<<1,l,mid,ql,qr,x);
if (mid+1<=qr) modify1(i<<1|1,mid+1,r,ql,qr,x);
}
 
void modify2(int i,int l,int r,int ql,int qr,int x)
{
if (ql<=l&&r<=qr) { put(x,i+4*n,0); return;}
int mid=(l+r)>>1;
if (ql<=mid) modify2(i<<1,l,mid,ql,qr,x);
if (mid+1<=qr) modify2(i<<1|1,mid+1,r,ql,qr,x);
}
 
void dijstra()
{
S=pos2[S];
for (int i=1;i<=cnt;i++) dis[i]=inf;
dis[S]=0; q.push((QQ){S,dis[S]});
while (!q.empty())
{
int x=q.top().x; q.pop();
if (vis[x]) continue;
vis[x]=1;
for (int i=v[x];i;i=e[i].ne)
{
int y=e[i].t;
if (dis[y]>dis[x]+e[i].l)
{
dis[y]=dis[x]+e[i].l;
q.push((QQ){y,dis[y]});
}
}
}
}
 
int main()
{
int m;
scanf("%d%d%d",&n,&m,&S);
build1(1,1,n); build2(1,1,n);
for (int i=1;i<=n;i++) put(pos2[i],pos1[i],0);
cnt=8*n;
for (int i=1;i<=m;i++)
{
int A,B,C,D;
scanf("%d%d%d%d",&A,&B,&C,&D);
int x=++cnt,y=++cnt;
modify1(1,1,n,A,B,x);
modify2(1,1,n,C,D,y);
put(x,y,1);
x=++cnt; y=++cnt;
modify1(1,1,n,C,D,x);
modify2(1,1,n,A,B,y);
put(x,y,1);
}
dijstra();
for (int i=1;i<=n;i++) printf("%d\n",dis[pos1[i]]);
return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值