题目链接:传送门
题目思路:
直接暴力连边,显然会超时,那么可以采用“源点”的建图思想,对于区间问题,可以利用线段树建图。
建立一颗 inTree 和 outTree ,得:
这样建图能保证初始时刻 [1,1] 可以到达 [1,2] ,[1,4] ,但是不能到达 其他叶子节点。
对于区间 连接 单点,则从inTree 的区间 连接至outTree的单点;对于单点 连接 区间 则从inTree 的单点 连接至 outTree的区间 ;
对于区间 连接 区间,则可以从 outTree 处理出来区间对应的节点集合,然后再 在inTree 中对应的区间 对集合中的点进行连边(也可以先处理inTree ,在outTree 中连边);
代码:(下面代码中,叶子节点是两棵树复用的)

1 #include<bits/stdc++.h> 2 #pragma GCC optimize(2) 3 using namespace std; 4 typedef long long LL; 5 typedef unsigned long long uLL; 6 typedef pair<int,int> pii; 7 typedef pair<LL,LL> pLL; 8 typedef pair<double,double> pdd; 9 const int N=1e5+5; 10 const int M=8e5+5; 11 const LL inf=1e16; 12 const LL mod=1e8+7; 13 const double eps=1e-8; 14 const long double pi=acos(-1.0L); 15 #define ls (i<<1) 16 #define rs (i<<1|1) 17 #define fi first 18 #define se second 19 #define pb push_back 20 #define eb emplace_back 21 #define mk make_pair 22 #define mem(a,b) memset(a,b,sizeof(a)) 23 LL read() 24 { 25 LL x=0,t=1; 26 char ch; 27 while(!isdigit(ch=getchar())) if(ch=='-') t=-1; 28 while(isdigit(ch)){ x=10*x+ch-'0'; ch=getchar(); } 29 return x*t; 30 31 } 32 LL dis[N<<3]; 33 int cnt,vis[N<<3],n,s,q; 34 struct node{ int l,r; }; 35 struct disx{ 36 LL x;int y; 37 friend bool operator < (disx X,disx Y) 38 { 39 return X.x>Y.x; 40 } 41 }; 42 node c[N<<3]; 43 vector<pii> e[N<<3]; 44 inline void add(int u,int v,int w) 45 { 46 e[u].eb(v,w); 47 } 48 void buildin(int &now,int l,int r) 49 { 50 if(l==r) return (void)(now=l); 51 now=++cnt;//printf("in = %d, %d %d ",now,l,r); 52 c[now].l=c[now].r=0; 53 int mid=l+r>>1; 54 buildin(c[now].l,l,mid); 55 buildin(c[now].r,mid+1,r); 56 add(c[now].l,now,0); 57 add(c[now].r,now,0); 58 } 59 void buildout(int &now,int l,int r) 60 { 61 if(l==r) return (void)(now=l); 62 now=++cnt;//printf("out = %d, %d %d ",now,l,r); 63 c[now].l=c[now].r=0; 64 int mid=l+r>>1; 65 buildout(c[now].l,l,mid); 66 buildout(c[now].r,mid+1,r); 67 add(now,c[now].l,0); 68 add(now,c[now].r,0); 69 } 70 void updin(int now,int l,int r,int ll,int rr,int x,int y) 71 { 72 if(ll<=l&&r<=rr) return add(now,x,y); 73 int mid=l+r>>1; 74 if(mid>=ll) updin(c[now].l,l,mid,ll,rr,x,y); 75 if(mid<rr) updin(c[now].r,mid+1,r,ll,rr,x,y); 76 } 77 void updout(int now,int l,int r,int ll,int rr,int x,int y) 78 { 79 if(ll<=l&&r<=rr) return add(x,now,y); 80 int mid=l+r>>1; 81 if(mid>=ll) updout(c[now].l,l,mid,ll,rr,x,y); 82 if(mid<rr) updout(c[now].r,mid+1,r,ll,rr,x,y); 83 } 84 void dijk() 85 { 86 priority_queue<disx> q; 87 for(int i=1;i<=cnt;i++) dis[i]=inf; 88 q.push(disx{dis[s]=0,s}); 89 while(!q.empty()) 90 { 91 int u=q.top().y; 92 q.pop(); 93 if(vis[u]) continue; //printf("u = %d ",u); 94 vis[u]=1; 95 for(auto x:e[u]) 96 { 97 //printf("%d -> %d ",u,x.fi); 98 int v=x.fi,w=x.se; 99 if(dis[v]>dis[u]+w) q.push(disx{dis[v]=dis[u]+w,v}); 100 } 101 } 102 } 103 int main() 104 { 105 n=read(),q=read(),s=read(); 106 cnt=n; 107 int rt1,rt2; 108 buildin(rt1,1,n); 109 buildout(rt2,1,n); 110 //printf("r1 = %d , r2 = %d ",rt1,rt2); 111 for(int i=1;i<=q;i++) 112 { 113 int t=read(); 114 if(t==1) 115 { 116 int v=read(),u=read(),w=read(); 117 add(v,u,w); 118 } 119 else if(t==2) 120 { 121 int v=read(),l=read(),r=read(),w=read(); 122 updout(rt2,1,n,l,r,v,w); 123 } 124 else 125 { 126 int v=read(),l=read(),r=read(),w=read(); 127 updin(rt1,1,n,l,r,v,w); 128 } 129 } 130 // puts("..."); 131 dijk(); 132 for(int i=1;i<=n;i++) 133 printf("%lld ",dis[i]==inf?-1:dis[i]); 134 printf(" "); 135 return 0; 136 }