[CF787D]Legacy
NOId1t1有这种线段树优化建边的部分分,然后发现还不会。。。
思想就是化为两棵线段树,一棵代表出一棵代表入。每棵树内部就正常那么连边,然后点连到区间就相当于把区间按线段树拆法拆成log个区间,内部yy一下就行了。
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<ll,int> P; const int N=500000; const ll inf=1e16; inline int read(){ int r=0,c=getchar(); while(!isdigit(c))c=getchar(); while(isdigit(c))r=r*10+c-'0',c=getchar(); return r; } struct Edge{ int to,nxt,w; }e[N<<2]; int n,m,S; int head[N<<2],cnt=1; void add(int u,int v,int w){ e[cnt]=(Edge){v,head[u],w}; head[u]=cnt++; } struct Node{ int l,r; }T[N<<2]; #define L T[o].l #define R T[o].r #define M (L+R>>1) #define ls o<<1 #define rs o<<1|1 void build(int o,int l,int r){ T[o]=(Node){l,r}; if(l==r){ add(o,o+N,0); add(o+N,o,0); return; } build(ls,L,M); build(rs,M+1,R); add(ls,o,0);add(o+N,(ls)+N,0); add(rs,o,0);add(o+N,(rs)+N,0); } int ql,qr,tmp,ww,tp; void find(int o){ if(ql<=L&&R<=qr){ if(tp<3)tmp=o; else tmp=o+N; return; } if(ql<=M)find(ls); if(qr>M) find(rs); } void upd(int o){ if(ql<=L&&R<=qr){ if(tp<3)add(tmp,o+N,ww); else add(o,tmp,ww); return; } if(ql<=M)upd(ls); if(qr>M) upd(rs); } ll dis[N<<2];bool vis[N<<2]; priority_queue<P,vector<P>,greater<P> >q; void dij(){ fill(dis,dis+(N<<1),inf); ql=qr=S;tp=1;find(1);S=tmp; q.push(P(dis[S]=0,S)); while(!q.empty()){ P x=q.top();q.pop(); ll d=x.first;int u=x.second; if(vis[u])continue;vis[u]=1; for(int i=head[u];i;i=e[i].nxt){ int v=e[i].to,w=e[i].w; if(d+w<dis[v]){ dis[v]=d+w; q.push(P(dis[v],v)); } } } } void init(){ n=read();m=read(); S=read(); build(1,1,n); while(m--){ tp=read(); int u,v,l,r; if(tp==1){ u=read();v=read();ww=read(); ql=qr=u;find(1); ql=qr=v;upd(1); } else{ u=read();l=read(),r=read();ww=read(); ql=qr=u;find(1); ql=l,qr=r;upd(1); } } } void prt(int o){ if(L==R){ if(dis[o+N]==inf)dis[o+N]=-1; printf("%lld ",dis[o+N]); return; } prt(ls);prt(rs); } int main(){ init(); dij(); prt(1); }