入树是指从叶子节点连有向边连向根,出树是指从根连有向边连向叶子节点,他们的每条边权都是0.如果有一个节点newnode连向出树的一个节点,表示这个节点newnode可以连向出树该节点所管的所有节点;如果有一个节点newnonde连向入树的一个节点,表示入树该节点所管的所有节点都可以连向这个节newnode。
所以,如果是点x连点y,就是x在入树的编号in_num【x】与y在出树的编号out_num【y】连边。如果是点x连向区间y,就是x在入树的编号in_num【x】与区间y在出树划分出来的log个点连边。如果是区间x连向点y,就是区间x在入树划分出来的log个点连向y在出树的编号out_num【y】。如果是区间x连向区间y,就是new一个节点newnode,让区间x在入树划分的log个节点连向newnode,再让newnode连向区间y在出树划分的log个节点。
注意点:应该让每个点到自己连一条边权为0的边,in_num【x】连out_num【x】边权为0.只能是入树连向出树,不能出树连入树。区间连区间如果是双向边需要建两个newnode,分别连双边,原因:设x区间连y区间,第一次连x,y,newnode1表示x可以连y,如果再让y连x用newnode1,表示y可以连x区间且y可以连y区间,可是实际上y并不能连y区间,只能连x区间,所以第二次连接要用newnode2。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
//#define int long long
typedef unsigned long long ull;
typedef pair<ll,ll> pii;
const int inf=0x3f3f3f3f;
const int N=1e6+10;
const int mod=1e9+7;
const ll INF=2e9+10;
mt19937_64 rd(23333);
uniform_real_distribution<double> drd(0.000001,0.99999);
int n,q,s,flag;
struct node{
int to,next,v;
}e[N*8];
int head[N*8],edge_cnt;
void add(int from ,int to,int v){
e[++edge_cnt]={to,head[from],v};
head[from]=edge_cnt;
}
int in_root,out_root,tree_cnt;
int ls[N*8],rs[N*8];
int in_num[N*8],out_num[N*8];
void build_in(int l,int r,int &cur){
cur=++tree_cnt;
if(l==r){
in_num[l]=cur;
return;
}
int mid=(l+r)>>1;
build_in(l,mid,ls[cur]);
build_in(mid+1,r,rs[cur]);
add(ls[cur],cur,0);//儿子连上父亲没有花费
add(rs[cur],cur,0);
}
void build_out(int l,int r,int &cur){
cur=++tree_cnt;
if(l==r){
out_num[l]=cur;
return;
}
int mid=(l+r)>>1;
build_out(l,mid,ls[cur]);
build_out(mid+1,r,rs[cur]);
add(cur,ls[cur],0);//父亲连儿子没有花费
add(cur,rs[cur],0);
}
void modify_in(int l,int r,int x,int y,int to,int v,int &cur){
if(x<=l&&y>=r){//多点到一点,in_tree is leaves to root
add(cur,to,v);
return;
}
int mid=(l+r)>>1;
if(x<=mid) modify_in(l,mid,x,y,to,v,ls[cur]);
if(y>mid) modify_in(mid+1,r,x,y,to,v,rs[cur]);
}
void modify_out(int l,int r,int x,int y,int from,int v,int &cur){
if(x<=l&&y>=r){//一点到多点,out_tree is root to leaves
add(from,cur,v);
return;
}
int mid=(l+r)>>1;
if(x<=mid) modify_out(l,mid,x,y,from,v,ls[cur]);
if(y>mid) modify_out(mid+1,r,x,y,from,v,rs[cur]);
}
int dis[N*8];
bool vis[N*8];
void dijkstra(int s){
int x=in_num[s];
for(int i=1;i<=tree_cnt;i++)
dis[i]=inf;
priority_queue<pii,vector<pii>,greater<pii> > q;
dis[x]=0;
q.push({0,x});
while(q.size()){
auto t=q.top();
q.pop();
int index=t.second;
if(vis[index]) continue;
vis[index]=1;
for(int i=head[index];i;i=e[i].next){
int to=e[i].to,v=e[i].v;
if(!vis[to]&&dis[to]>dis[index]+v){
dis[to]=dis[index]+v;
q.push({dis[to],to});
}
}
}
}
void solve(){
cin>>n>>q>>s;
build_in(1,n,in_root);
build_out(1,n,out_root);
for(int i=1;i<=n;i++){
add(in_num[i],out_num[i],0);//点到点本身没有花费
add(out_num[i],in_num[i],0);
}
while(q--){
/*cin>>flag;
int x,y,l,r,v;
if(flag==1){
cin>>x>>y>>v;
add(in_num[x],out_num[y],v);
}
else if(flag==2){
cin>>x>>l>>r>>v;
modify_out(1,n,l,r,in_num[x],v,out_root);
}
else{
cin>>x>>l>>r>>v;
modify_in(1,n,l,r,out_num[x],v,in_root);
}*/
int x,y,l,r,v=1;
cin>>l>>r>>x>>y;
int newnode=++tree_cnt;
modify_in(1,n,l,r,newnode,v,in_root);
modify_out(1,n,x,y,newnode,v,out_root);
newnode=++tree_cnt;
modify_in(1,n,x,y,newnode,v,in_root);
modify_out(1,n,l,r,newnode,v,out_root);
}
dijkstra(s);
for(int i=1;i<=n;i++){
if(dis[out_num[i]]==inf) cout<<"-1 ";
else cout<<dis[out_num[i]]/2<<endl;
}
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t=1;
//cin>>t;
while(t--){
solve();
}
return 0;
}