专栏文章
题解 P6348 [PA2011]Journeys
P6348题解参与者 17已保存评论 20
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 20 条
- 当前快照
- 1 份
- 快照标识符
- @mk262qs1
- 此快照首次捕获于
- 2026/01/06 13:46 上个月
- 此快照最后确认于
- 2026/01/06 13:46 上个月
线段树优化建图
我们可以从最朴素的思路开始想起。
0.0 暴力建图
对于一堆道路 ,两两连边。
1.0 连向公共边
对于一堆道路 ,我们让 连向一个虚拟点 ,
再从 向 连边。
但是这样总共要连 条边,肯定会炸。
所以要想办法优化连边的边数。
2.0 线段树优化建图
这个时候线段树重磅出击。
-
性质 2.1 对于一个区间的点 ,一个包含它的区间 连向的点,那么 也能连向。
-
性质 2.2 对于一个区间的点 ,另一个点 如果能到达一个包含 区间 ,那么点 也能到达 。
由此,我们便可建出两棵线段树,进树和出树。
同时,这也是为什么进树从父节点连向子节点,二出树从子节点连向父节点的原因。
不把两棵树建到一块,是为了防止直接顺着线段树直接走完所有点。
而对于一个区间 它在进树、出树本质上是一个点。
所以经过某条边到达进树后,可以回到出树继续走下一条边。
也就是说进树的点直接连向对应的出树的点。


图中绿色的边权之标上 ,但是最后答案要除以 。
因为从 连到 经过两条绿边,路程算了 ,但其实只用算一条,所以要除以 。
或者连向绿点的边和绿点连出的边任意一个标权值也可以。
code
CPP#include<bits/stdc++.h>
#define ls(o) (o<<1)
#define rs(o) (o<<1|1)
//#define int long long
using namespace std;
const int N=500010,M=4200010;
int n,m,p,out,num[N];
struct edge{
int v,w;
};
vector<edge> g[M];
void build_in(int o,int l,int r){
if(l==r)return;
int mid=l+r>>1;
build_in(ls(o),l,mid);
build_in(rs(o),mid+1,r);
g[o].push_back({ls(o),0});
g[o].push_back({rs(o),0});
}
void build_out(int o,int l,int r){
g[o].push_back({o+n*4,0});
if(l==r)return (void)(num[l]=o+n*4);
int mid=l+r>>1;
build_out(ls(o),l,mid);
build_out(rs(o),mid+1,r);
g[ls(o)+n*4].push_back({o+n*4,0});
g[rs(o)+n*4].push_back({o+n*4,0});
}
void merge1(int o,int l,int r,int x,int y,int k){
if(l>=x&&r<=y)return (void)(g[k].push_back({o,1}),g[o+n*4].push_back({k+1,1}));
int mid=l+r>>1;
if(mid>=x)merge1(ls(o),l,mid,x,y,k);
if(mid<y)merge1(rs(o),mid+1,r,x,y,k);
}
void merge2(int o,int l,int r,int x,int y,int k){
if(l>=x&&r<=y)return (void)(g[k+1].push_back({o,1}),g[o+n*4].push_back({k,1}));
int mid=l+r>>1;
if(mid>=x)merge2(ls(o),l,mid,x,y,k);
if(mid<y)merge2(rs(o),mid+1,r,x,y,k);
}
int d[M];
bool vis[M];
deque<int> q;
void dijstra(int s){
memset(d,127,sizeof(d));
d[s]=0;
q.push_front(s);
while(!q.empty()){
int u=q.front();
q.pop_front();
// if(vis[u])continue;
// vis[u]=1;
for(int i=0;i<g[u].size();i++){
int v=g[u][i].v;
// if(vis[v])continue;
int w=g[u][i].w;
if(d[v]>d[u]+w){
d[v]=d[u]+w;
if(w==1)q.push_back(v);
else q.push_front(v);
}
}
}
}
inline char nc(){
static char buf[1000010],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000010,stdin),p1==p2)?EOF:*p1++;
}
//#define nc getchar
inline int read(){
register int s=0,w=0;
static char ch=nc();
for(;!isdigit(ch);)ch=nc();
for(;isdigit(ch);){
s=(s<<1)+(s<<3)+(ch^48);
ch=nc();
}
return w?-s:s;
}
signed main(){
n=read(),m=read(),p=read();
build_in(1,1,n);
build_out(1,1,n);
for(register int a,b,c,d,i=1;i<=m;++i){
a=read(),b=read(),c=read(),d=read();
merge1(1,1,n,a,b,n*8+i*2);
merge2(1,1,n,c,d,n*8+i*2);
}
dijstra(num[p]);
for(register int i=1;i<=n;++i)printf("%d\n",d[num[i]]/2);
// for(int i=1;i<=tot;i++){
// printf("%lld %lld %lld %lld:\n",i,tr[i].l,tr[i].r,g[i].size());
// for(int j=0;j<g[i].size();j++)printf("%lld %lld\n",g[i][j].v,g[i][j].w);
// }
}
相关推荐
评论
共 20 条评论,欢迎与作者交流。
正在加载评论...