前言
百川到海,天下归一
解析
线段树优化建图是用于对一个区间的点连边时的优化方法
建一棵in树一棵出树分别往上和下指即可
大概长这样
(pia的洛谷的照片)
建树
正常动态开点即可
void build(int &k,int l,int r){tr[k=++tot]=(tree){0,0};if(l==r){addline(k,l);return;}build(tr[k].ls,l,mid);build(tr[k].rs,mid+1,r);addline(k,tr[k].ls);addline(k,tr[k].rs);//printf("k=%d l=%d r=%d ls=%d rs=%d\n",k,l,r,tr[k].ls,tr[k].rs);return;
}
连边
和线段树的通常操作很类似
void add(int k,int l,int r,int x,int y,int o){//printf("add:k=%d l=%d r=%d x=%d y=%d o=%d\n",k,l,r,x,y,o);if(x<=l&&r<=y){//printf(" o=%d k=%d\n",o,k);addline(o,k);return;}if(x<=mid) add(tr[k].ls,l,mid,x,y,o);if(y>mid) add(tr[k].rs,mid+1,r,x,y,o);return;
}
区间对区间连边
不需要对入树和出树两两相连,只需要新开一个虚点,都对虚点连边即可
这样总的加边数就是单log的
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=5e5+100;
const int M=1e6+100;
ll read(){ll x=0,f=1;char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)){x=x*10+(c^48);c=getchar();}return x*f;
}inline void Max(int &x,int y){if(x<y) x=y;}int n;
struct node{int to,nxt,w;
}p[N*205];
int fi[N<<3],cnt;
inline void addline(int x,int y,int w){//if(w)//printf("%d %d %d\n",x,y,w);p[++cnt]=(node){y,fi[x],w};fi[x]=cnt;return;
}
int ls[N<<3],rs[N<<3],rin,rout,tot;
#define mid ((l+r)>>1)
void build(int &k,int l,int r,int op){k=++tot;if(l==r){//printf("(%d %d) k=%d ls=%d rs=%d op=%d\n",l,r,k,0,0,op);if(op==0) addline(k,l,0);else addline(l,k,0);return;}build(ls[k],l,mid,op);build(rs[k],mid+1,r,op);if(op==0){addline(k,ls[k],0);addline(k,rs[k],0);}else{addline(ls[k],k,0);addline(rs[k],k,0);}//printf("(%d %d) k=%d ls=%d rs=%d op=%d\n",l,r,k,ls[k],rs[k],op);return;
}
void add(int k,int l,int r,int x,int y,int o,int op){if(x<=l&&r<=y){if(op==0) addline(o,k,op);else addline(k,o,op);return;}if(x<=mid) add(ls[k],l,mid,x,y,o,op);if(y>mid) add(rs[k],mid+1,r,x,y,o,op);return;
}
int s,m;
int dis[N<<3],vis[N<<3];
deque<int>q;
int main(){#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);#endifmemset(fi,-1,sizeof(fi));cnt=-1;n=read();m=read();s=read();tot=n;build(rin,1,n,0);build(rout,1,n,1);for(int i=1;i<=m;i++){int a=read(),b=read(),c=read(),d=read();/*for(int j=a;j<=b;j++){for(int k=c;k<=d;k++){if(j==k) continue;addline(j,k,1);addline(k,j,1);} }*/int o=++tot;add(rin,1,n,a,b,o,0);add(rout,1,n,c,d,o,1);o=++tot;add(rin,1,n,c,d,o,0);add(rout,1,n,a,b,o,1);/*find(rout,1,n,a,b,c,d);find(rout,1,n,c,d,a,b);*/}memset(dis,0x3f,sizeof(dis));q.push_back(s);dis[s]=0;while(!q.empty()){int now=q.front();q.pop_front();if(vis[now]) continue;vis[now]=1;for(int i=fi[now];~i;i=p[i].nxt){int to=p[i].to;if(dis[now]+p[i].w>=dis[to]) continue;dis[to]=dis[now]+p[i].w;if(p[i].w) q.push_back(to);else q.push_front(to);}}for(int i=1;i<=n;i++) printf("%d\n",dis[i]);
}
/**/