tomcat8.5.57原始碼閱讀筆記5.1 - 管道
阿新 • • 發佈:2020-08-23
前言
第一道用線段樹優化建邊做的題,還是比較有記錄意義的
當然也有對Rick姥爺的膜拜 orz
話說Rick為啥會給Morty留遺產
題目
講解
首先操作一有手就行
問題是點連區間和區間連點的操作不好搞
區間?你會想到什麼?
線段樹!
直接讓線段樹上的點連邊,表示點連區間和區間連點
但是我們發現一個問題,大區間可以由小區間組成,這會引起什麼?
大區間可以走向單點,組成它的小區間也可以走向單點
單點可以走向小區間,單點也可以走向大區間
細品這兩句話↑
所以我們需要兩棵線段樹分別維護走出去(從線段樹走出去到單點,後者同理)和走進來
一切都變得簡單了,注意long long和陣列大小
我才不會用vector去卡空間,哼
程式碼
int head[MAXN * 9],tot; struct edge { int v,w,nxt; }e[MAXN * 40]; void Add_Edge(int x,int y,int z) { e[++tot].v = y; e[tot].w = z; e[tot].nxt = head[x]; head[x] = tot; } int lc[MAXN * 9],rc[MAXN * 9],cnt; int Build(int l,int r,int t) { if(l == r) return l; int mid = (l+r) >> 1; int x = ++cnt; lc[x] = Build(l,mid,t); rc[x] = Build(mid+1,r,t); if(t == 1) Add_Edge(x,lc[x],0),Add_Edge(x,rc[x],0);//點連區間,往下走 else Add_Edge(lc[x],x,0),Add_Edge(rc[x],x,0);//區間連點,往上走 return x; } void update(int x,int l,int r,int ql,int qr,int ID,int val,int t) { if(ql <= l && r <= qr) { if(t == 1) Add_Edge(ID,x,val); else Add_Edge(x,ID,val); return; } int mid = (l+r) >> 1; if(ql <= mid) update(lc[x],l,mid,ql,qr,ID,val,t); if(mid+1 <= qr) update(rc[x],mid+1,r,ql,qr,ID,val,t); } LL dis[MAXN * 9]; struct node { int u;LL val; node(){} node(int u1,LL val1){ u = u1; val = val1; } bool operator < (const node &px)const{ return val > px.val; } }; void dijkstra() { for(int i = 1;i <= cnt;++ i) dis[i] = INF; priority_queue<node> q; q.push(node(S,dis[S] = 0)); while(!q.empty()) { node t = q.top(); q.pop(); if(t.val > dis[t.u]) continue; for(int i = head[t.u]; i ;i = e[i].nxt) if(dis[e[i].v] > dis[t.u] + e[i].w) q.push(node(e[i].v,dis[e[i].v] = dis[t.u] + e[i].w)); } } int main() { // freopen(".in","r",stdin); // freopen(".out","w",stdout); n = Read(); m = Read(); S = Read(); cnt = n; rt1 = Build(1,n,1); rt2 = Build(1,n,2); while(m--) { int opt = Read(),u = Read(),l = Read(),r = Read(); if(opt == 1) Add_Edge(u,l,r); else if(opt == 2) update(rt1,1,n,l,r,u,Read(),1); else update(rt2,1,n,l,r,u,Read(),2); } dijkstra(); for(int i = 1;i <= n;++ i) Put(dis[i] == INF ? -1 : dis[i],' '); return 0; }