1. 程式人生 > >【NOI2018day1】歸程(最短路+kruskal重構樹+並查集+倍增)

【NOI2018day1】歸程(最短路+kruskal重構樹+並查集+倍增)

Problem

  給定一個n(2105)個節點、m(4105)條邊的無向連通圖,用l(104),a(109)描述一條邊的長度、海拔
  給定Q(4105)天,每天給出出發節點v和水位線p。所有海拔**不超過**p的邊都會被淹。Yazid要回到位於1號節點的家。他在點v有輛車,但不能駛過被淹的邊。Yazid 可以在任意節點下車,這樣接下來他就可以步行經過有積水的邊。但車會被留在他下車的節點並不會再被使用。

  • 需要特殊說明的是,第二天車會被重置,這意味著:
    • 車會在新的出發點被準備好。
    • Yazid 不能利用之前在某處停放的車。

求最小的步行經過的邊的總長度。部分資料強制線上。有多組資料,但資料組數T≤3。

Solution

  • 首先,可以以1為起點對原圖做一遍單源最短路,求出所有點到1的dis。據說spfa會被卡,所以宜使用穩定的dijkstra。
  • 然後,若我們能求出所有v能到達的點,並知道這些點的dis的min,此問題便迎刃而解。
  • 可以使用kruskal重構樹。
  • 首先,對所有邊按照海拔從大到小排序。初始化fa陣列,令圖中每個點均為根。
  • 順序掃一遍邊集陣列。對於一條u,v間海拔為a的邊,先找出u,v所在子樹的根fu,fv,然後新建一個節點num,令fu為num的左兒子,fv為num的右兒子,且fu、fv連向num的邊的邊權均為a。
  • 為加速找根過程,使用並查集優化。
  • 經過上述操作,我們就得出一棵二叉樹。顯然,樹上每個節點到根的路徑上的邊權是單調遞減的(我們優先處理了海拔較高的邊)。
  • 對於某個詢問v,p,應從v往上走,直至走到不能再走(被水淹了)為止。因為若此時的邊被水淹了,則上面的邊肯定也被水淹了(權值單調遞減)。這樣可以用倍增。
  • 設這樣走到的點為x,則Yazid通過開車能且僅能到達以x為根的子樹中的點。可以預先dfs一遍,求出以每個點為根的子樹中所有點的dis的min值。
  • 時間複雜度:O(T(nlog2n+mα(n)+Q))

Code

#include <cstdio>
#include <cctype> #include <cstring> #include <queue> #include <vector> #include <algorithm> #define fo(i,a,b) for(i=a;i<=b;i++) #define fd(i,a,b) for(i=a;i>=b;i--) #define clear(a) fo(ii,1,n)a[ii]=0 #define cle(a) memset(a,0,sizeof a) #define rep(i,x) for(edg *i=x; i; i=i->ne) #define MIN(x,y) x=min(x,y) using namespace std; typedef long long ll; const int N=4e5+1; const ll inf=0x7FFFFFFF; int T,i,n,m,u,v,a,ii,x,y,num,Q,K,S,v0,p0,p; ll l,ans,dis[N]; struct edge { int u,v,a; ll l; }e[N]; struct edg { int to; ll l; edg *ne; inline edg(int to,ll l,edg *ne) : to(to), l(l), ne(ne){} }*fin[N]; template <class T> inline void read(T &x) { char ch=getchar(); x=0; for(;!isdigit(ch);ch=getchar()); for(;isdigit(ch);ch=getchar()) x=(x<<3)+(x<<1)+(ch^48); } inline void link(int x,int y) { fin[x]=new edg(y,l,fin[x]); } struct node { int i; ll dis; inline node(int _i,ll _dis){i=_i; dis=_dis;} }; struct cmp1 { inline bool operator ()(const node &a,const node &b){return a.dis>b.dis;} }; priority_queue <node,vector<node>,cmp1> P; bool vis[N]; void dijkstra() { while(!P.empty())P.pop(); P.push(node(1,0)); clear(vis); memset(dis,127,sizeof dis); dis[1]=0; while(!P.empty()) { node t=P.top(); P.pop(); int x=t.i; ll d=t.dis; if(vis[x]) continue; vis[x]=1; rep(i,fin[x]) { y=i->to; l=i->l; if(!vis[y]&&dis[y]>d+l) { dis[y]=d+l; P.push(node(y,dis[y])); } } } } int fa[N],fu,fv,L[N],R[N],anc[N][18],low[N][18]; ll mi[N]; inline bool cmp(edge a,edge b){return a.a>b.a;} int gef(int x) { return fa[x]==x ? x : fa[x]=gef(fa[x]); } void kruskal() { sort(e+1,e+m+1,cmp); cle(anc); cle(low); cle(L); cle(R); int i; fo(i,1,n)fa[i]=i; fo(i,1,m) { u=e[i].u; v=e[i].v; fu=gef(u);fv=gef(v); if(fu!=fv) { anc[fu][0]=fa[fu]=anc[fv][0]=fa[fv]=fa[num+1]=++num; low[fu][0]=low[fv][0]=e[i].a; L[num]=fu; R[num]=fv; } } } void dfs(int x) { int i,f=anc[x][0]; mi[x]=dis[x]; fo(i,1,17) { if(!f) break; low[x][i]=low[f][i-1]; f=anc[x][i]=anc[f][i-1]; } if(L[x]) dfs(L[x]), MIN(mi[x],mi[L[x]]); if(R[x]) dfs(R[x]), MIN(mi[x],mi[R[x]]); } int main() { for(read(T);T;T--) { read(n); read(m); clear(fin); fo(i,1,m) { read(u), read(v), read(l), read(a); e[i].u=u,e[i].v=v,e[i].l=l,e[i].a=a; link(u,v); link(v,u); } dijkstra(); num=n; kruskal(); dfs(num); read(Q); read(K); read(S); ans=0; fo(i,1,Q) { read(v0); v=(v0+K*ans-1)%n+1; read(p0); p=(p0+K*ans)%(S+1); fd(ii,17,0) if( anc[v][ii] && low[v][ii]>p ) v=anc[v][ii]; printf("%lld\n",ans=mi[v]); } } }

相關推薦

NOI2018day1歸程短路+kruskal重構++倍增

Problem   給定一個n(≤2∗105)n(≤2∗105)個節點、m(≤4∗105)m(≤4∗105)條邊的無向連通圖,用l(≤104)l(≤104),a(≤109)a(≤109)描述一條邊的長度、海拔。   給定Q(≤4∗105)Q(≤4∗105)天

BZOJ2750HAOI2012道路短路+拓撲

容易想到列舉所有起點 做最短路 然後列舉邊統計次數 一條邊(x,y)的貢獻 肯定是 s到x最短路的方案數 乘上 s到其他點但經過了y的最短路 對於前者 每個點可以從前一個點遞推過來 只要滿足dis[vis]==dis[now]+edge[u].val 當一個點被所有入邊都統計了一次後 就可以搜他了(拓撲思想)

bzoj1604[Usaco2008 Open]Cow Neighborhoods 奶牛的鄰居 +Treap/STL-set

多少 aps stl oot 絕對值 cmp rac 維護 屬於 題目描述 了解奶牛們的人都知道,奶牛喜歡成群結隊.觀察約翰的N(1≤N≤100000)只奶牛,你會發現她們已經結成了幾個“群”.每只奶牛在吃草的時候有一個獨一無二的位置坐

openjudgeC15C Rabbit's Festival CDQ分治+

amp rabbit class printf sdn 題解 {} .net log 題目鏈接:http://poj.openjudge.cn/practice/C15C/ 題意:n 點 m 邊 k 天。每條邊在某一天會消失(僅僅那一天消失)。問每一天有多少對點可以相互到達

NOI2018歸程kruskal重構+短路+樹上倍增

總的來說 從v通往1的道路 分為了步行和開車 也就是說 一個點u 他能作為分界點 當且僅當存在一條路徑(u,v)的海拔全部高於當天水位線 且(u,1)是最短路 很顯然 這是一個與瓶頸有關的問題 不難想到Kruskal重構樹 由於瓶頸是海拔 所以我們先建出以海拔為關鍵字的重構樹 由於是個小根堆 所以一個節點 子

2018.11.05校內模擬規避短路計數容斥正難則反

傳送門 解析: 首先直接統計並不好做,考慮反著做,先求出總共的方案數,然後減去相遇的方案數。 總方案數就是SSS到TTT的最短路數量的平方(兩人分別作選擇)。 首先這是個計數類問題,先做一個最短路計數。 令distSudistS_udistSu​表示SSS到u

POJ 2502Subway短路dij

Description You have just moved from a quiet Waterloo neighbourhood to a big, noisy city. Instead of getting to ride your bike to

POJ3463 Sightseeing 短路+比短路大一的路短路 or 短路+DP

BAPC 2006 Qualification題型:求最短路以及比最短路長度大一的次短路,並要求計數。傳送門:【POJ】3463 Sightseeing 題目大意:給你n個點m條邊的有向圖(unidirectional是有向!),讓你求最短路以及長度比最短路大一的路的數量。題目保證數量不超過10^9。(2 ≤

BZOJ4144[AMPPZ2014]Petrol 短路+離線+小生成樹

判斷 eof etc while cpp ont 原來 有一個 style 【BZOJ4144】[AMPPZ2014]Petrol Description 給定一個n個點、m條邊的帶權無向圖,其中有s個點是加油站。 每輛車都有一個油量上限b,即每次行走距離不能超過

NOI2018歸程克魯斯卡爾重構

復雜度 修改 復雜 print noi truct dfs second getch 【NOI2018】歸程(克魯斯卡爾重構樹) 題面 洛谷 題解 我在現場竟然沒有把這道傻逼題給切掉,身敗名裂。 因為這題就是克魯斯卡爾重構樹的模板題啊 我就直接簡單的說一下把 首先發現答案就

NOIP2017逛公園 短路+DP

() next sizeof truct c++ pre 長度 div 分層圖 誒,去年場上不會處理$0$的環,只拿了$60$有點可惜。 我們先不管邊邊權為$0$的邊。 我們先跑一次最短路,令$dis[u]$表示從$1$至$u$的最短路的長度。 那麽根據題目的要求,從

CF1076DEdge Deletion 短路+貪心

題目大意:給定 N 個點 M 條邊的無向簡單聯通圖,留下最多 K 條邊,求剩下的點裡面從 1 號頂點到其餘各點最短路大小等於原先最短路大小的點最多怎麼構造。 題解:我們可以在第一次跑 dij 時直接採用貪心策略,即:若當前答案集合的大小小於 K 且優先佇列非空,則繼續優先佇列BFS,每次把一條邊加入到答案集

2018.10.10POJ1149PIGS大流玄學建圖

傳送門 解析: 今天DZYODZYODZYO講的最難的一道題,課上怎麼都想不出來的坑題。。。 建圖真是太巧妙了。 思路: 首先對於豬圈中初始豬的數量,這很好解決,直接從源點連一條容量為初始數量的邊就可

2018.10.10HDU4322Candy大費用大流建圖

傳送門 解析: 隱藏極深的一個匹配問題。其實就是將糖果和小朋友匹配,問能否滿足所有小朋友的需要。 思路: 看出來是一個匹配問題,那就直接考慮網路流。 首先先考慮k=2k=2k=2怎麼做 顯然當k=2k=2k=2時,我們儘量用小朋友喜歡的糖去提升他的快樂值,最後

演算法單源短路——Dijkstra

對於固定起點的最短路演算法,我們稱之為單源最短路演算法。單源最短路演算法很多,最常見的就是dijkstra演算法。 dijkstra主要用的是一種貪心的思想,就是說如果i...s...t...j是最短路,那麼i和j之間的任意兩點s,t之間也一定是最短路,非常好證,如果s,t

練習angularjs基本的$http使用jsonp跨域,使用jsonp跨域獲取天氣採用百度地圖天氣api,路由功能實現單頁面不跳轉切換

1.最基本的$http使用jsonp跨域 <body ng-app="app"> <div ng-controller="controller"> </div> <script src="angularjs/angularjs.js

PythonHackBack獲取暴力破解服務器密碼的IP來源

split time get main ports import var api pre 1、前言 又在0x00sec上翻到好東東。 https://0x00sec.org/t/python-hackback-updated/882 帖子裏的腳本會得到那些暴力服務器密碼失敗

51Nod - 1416兩點 dfs 或 +dfs

題幹: 福克斯在玩一款手機解迷遊戲,這個遊戲叫做”兩點”。基礎級別的時候是在一個n×m單元上玩的。像這樣:    每一個單元有包含一個有色點。我們將用不同的大寫字母來表示不同的顏色。 這個遊戲的關鍵是要找出一個包含同一顏色的環。看上圖中4個藍點,形成了一個環。

Buy a Ticket 短路設虛擬節點+Dijkstra優先佇列優化

Musicians of a popular band "Flayer" have announced that they are going to "make their exit" with a world tour. Of course, they will visit Berland as

POJ2912Rochambeau帶權+列舉

題目連結 Rochambeau Time Limit: 5000MS Memory Limit: 65536K Total Submissions:4932 Accepted: 1699 Description N children