Description
Input
Output
Sample Input
1 2 4 5
5 5 4 4
1 1 3 3
Sample Output
1
2
0
1
分析:
dalao’s blog
显然最短路问题
但是如果我们对于区间暴力连边,边数会高达
n2m
n
2
m
于是可以线段树来优化:两棵线段树:进树,出树
进树:从父亲向儿子连边(边权为0),表示能达到该区间就能达到该区间的子区间
出树:从儿子向父亲连边(边权为0),表示能从该区间出发就能从该区间的父区间出发
两树之间:进树向出树的对应区间连边(边权为0),表示到达该区间后,还能从该区间继续出发
对于给出的边,从出树中找到对应区间,向新建的辅助点连边(边权为0),从辅助点向进树的对应区间连边(边权为1),由于是无向边,要连两次
例如5个节点中连边
[2,3]−>[4,5]
[
2
,
3
]
−
>
[
4
,
5
]
:
之后dijsktra,答案就是进树的叶子节点距离
tip
蜜汁CE,鬼知道为什么。。。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
const int N=5000010;
const int M=30000005;
struct node{
int y,nxt,v;
};
node way[M];
int st[N],tot=0,cnt,out[N],in[N];
int n,m,s;
struct point{
int u,dis;
point(int uu=0,int d=0) {
u=uu;dis=d;
}
bool operator <(const point &b) const {
return dis>b.dis;
}
};
priority_queue<point> q;
void add(int u,int w,int z) {
tot++;way[tot].y=w;way[tot].v=z;way[tot].nxt=st[u];st[u]=tot;
}
struct Tree{
struct po{int l,r,pos;};
po t[2000005];
void build(int bh,int l,int r,int opt) {
t[bh].pos=++cnt;
t[bh].l=l; t[bh].r=r;
if (l==r) {
if (opt==0) out[l]=cnt; //每个编号对应的线段树上的点
if (opt==1) in[l]=cnt;
return;
}
int mid=(l+r)>>1;
build(bh<<1,l,mid,opt);
build(bh<<1|1,mid+1,r,opt);
if (opt==0) //出树(子连父)
{
add(t[bh<<1].pos,t[bh].pos,0);
add(t[bh<<1|1].pos,t[bh].pos,0);
}
else //入树(父连子)
{
add(t[bh].pos,t[bh<<1].pos,0);
add(t[bh].pos,t[bh<<1|1].pos,0);
}
}
void change(int bh,int l,int r,int L,int R,int w,int opt) {
if (l>=L&&r<=R) {
if (opt==0) add(t[bh].pos,w,0);
else add(w,t[bh].pos,1);
return;
}
int mid=(l+r)>>1;
if (L<=mid) change(bh<<1,l,mid,L,R,w,opt);
if (R>mid) change(bh<<1|1,mid+1,r,L,R,w,opt);
}
};
Tree t1,t2;
int dis[N];
bool vis[N];
void dij() {
s=in[s]; //起点
memset(dis,0x33,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[s]=0;
q.push(point(s,0));
while (!q.empty()) {
point now=q.top(); q.pop();
if (vis[now.u]) continue;
vis[now.u]=1;
int u=now.u;
for (int i=st[u];i;i=way[i].nxt)
if (dis[way[i].y]>dis[u]+way[i].v) {
dis[way[i].y]=dis[u]+way[i].v;
q.push(point(way[i].y,dis[way[i].y]));
}
}
for (int i=1;i<=n;i++)
printf("%d\n",dis[in[i]]);
}
int main()
{
scanf("%d%d%d",&n,&m,&s);
int a,b,c,d;
cnt=0; //总结点数
t1.build(1,1,n,0); t2.build(1,1,n,1);
for (int i=1;i<=n;i++) add(in[i],out[i],0);
for (int i=1;i<=m;i++) {
scanf("%d%d%d%d",&a,&b,&c,&d);
t1.change(1,1,n,a,b,++cnt,0); //出树
t2.change(1,1,n,c,d,cnt,1); //入树
t1.change(1,1,n,c,d,++cnt,0);
t2.change(1,1,n,a,b,cnt,1);
}
dij();
return 0;
}
重构了代码,减少了一些无用的变量(AC代码)
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
const int N=5000010;
const int M=30000010;
struct node{
int y,nxt,v;
};
node way[M];
int n,m,s,cnt=0,st[N],tot=0,pos[N];
void add(int u,int w,int z) {
tot++;way[tot].y=w;way[tot].v=z;way[tot].nxt=st[u];st[u]=tot;
}
void build(int bh,int l,int r,int opt) {
if (l==r) {
if (!opt) pos[l]=bh;
else add(bh+4*n,bh,0); //入树->出树
return;
}
int mid=(l+r)>>1;
build(bh<<1,l,mid,opt);
build(bh<<1|1,mid+1,r,opt);
int lc=bh<<1,rc=bh<<1|1;
if (!opt) //出树
{
add(lc,bh,0);
add(rc,bh,0);
}
else
{
add(bh+4*n,lc+4*n,0);
add(bh+4*n,rc+4*n,0);
}
}
void change(int bh,int l,int r,int L,int R,int w,int opt) {
if (l>=L&&r<=R) {
if (!opt) add(bh,w,0);
else add(w,bh+4*n,1);
return;
}
int mid=(l+r)>>1;
if (L<=mid) change(bh<<1,l,mid,L,R,w,opt);
if (R>mid) change(bh<<1|1,mid+1,r,L,R,w,opt);
}
struct point{
int u,dis;
point(int uu=0,int d=0) {
u=uu;dis=d;
}
bool operator <(const point &b) const {
return dis>b.dis;
}
};
priority_queue<point> q;
int dis[N];
bool vis[N];
void dij() {
s=pos[s]; //起点
memset(dis,0x33,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[s]=0;
q.push(point(s,0));
while (!q.empty()) {
point now=q.top(); q.pop();
if (vis[now.u]) continue;
vis[now.u]=1;
int u=now.u;
for (int i=st[u];i;i=way[i].nxt)
if (dis[way[i].y]>dis[u]+way[i].v) {
dis[way[i].y]=dis[u]+way[i].v;
q.push(point(way[i].y,dis[way[i].y]));
}
}
for (int i=1;i<=n;i++)
printf("%d\n",dis[pos[i]]);
}
int main() {
scanf("%d%d%d",&n,&m,&s);
build(1,1,n,0); build(1,1,n,1);
int a,b,c,d;
cnt=n<<3;
for (int i=1;i<=m;i++) {
scanf("%d%d%d%d",&a,&b,&c,&d);
change(1,1,n,a,b,++cnt,0); change(1,1,n,c,d,cnt,1);
change(1,1,n,c,d,++cnt,0); change(1,1,n,a,b,cnt,1);
}
dij();
return 0;
}