NOI2018 歸程 可持久化並查集

2022-05-19 19:08:29 字數 4022 閱讀 7459

## 題目描述

本題的故事發生在魔力之都,在這裡我們將為你介紹一些必要的設定。 魔力之都可以抽象成乙個n 個節點、m 條邊的無向連通圖(節點的編號從 1至 n)。我們依次用 l,a描述一條邊的長度、海拔。 作為季風氣候的代表城市,魔力之都時常有雨水相伴,因此道路積水總是不可避免 的。由於整個城市的排水系統連通,因此有積水的邊一定是海拔相對最低的一些邊。我們用水位線來描述降雨的程度,它的意義是:所有海拔不超過水位線的邊都是有積水的。

yazid 是一名來自魔力之都的oier,剛參加完ion2018 的他將踏上歸程,回到他 溫暖的家。 yazid 的家恰好在魔力之都的 1 號節點。對於接下來 q天,每一天yazid 都會告訴你他的出發點 v,以及當天的水位線 p 。 每一天,yazid 在出發點都擁有一輛車。這輛車由於一些故障不能經過有積水的邊。 yazid 可以在任意節點下車,這樣接下來他就可以步行經過有積水的邊。但車會被留在他下車的節點並不會再被使用。 需要特殊說明的是,第二天車會被重置,這意味著:

輸入格式:

單個測試點中包含多組資料。輸入的第一行為乙個非負整數 t ,表示資料的組數。

接下來依次描述每組資料,對於每組資料:

第一行 2 個非負整數 n,m分別表示節點數、邊數。

接下來 m 行,每行 4 個正整數 u,v,l,a描述一條連線節點 u,v 的、長度為 l、海拔為 a 的邊。 在這裡,我們保證 1≤u,v≤n 。

接下來一行 3 個非負數 q,k,s其中 q 表示總天數, k∈0,1 是乙個會在下面被用到的係數, s 表示的是可能的最高水位線。

接下來 q 行依次描述每天的狀況。每行 2 個整數 v0;p0 描述一天:

這一天的出發節點為 v=(v0+k×lastans−1)modn+1。

這一天的水位線為 p=(p0+k×lastans)mod(s+1)。

其中lastans表示上一天的答案(最小步行總路程)。特別地,我們規定第 1 天時lastans = 0。 在這裡,我們保證 1≤v0≤n,0≤p0≤s1 。

對於輸入中的每一行,如果該行包含多個數,則用單個空格將它們隔開。

輸出格式:

依次輸出各組資料的答案。對於每組資料:

輸入樣例#1:

14 3

1 2 50 1

2 3 100 2

3 4 50 1

5 0 2

3 02 1

4 13 1

3 2輸出樣例#1:050

20050

150輸入樣例#2:

15 5

1 2 1 2

2 3 1 2

4 3 1 2

5 3 1 2

1 5 2 1

4 1 3

5 15 2

2 04 0

輸出樣例#2:02

31【樣例1 解釋】 第一天沒有降水,yazid 可以坐車直接回到家中。

第二天、第三天、第四天的積水情況相同,均為連線1; 2 號節點的邊、連線3; 4 號 點的邊有積水。

對於第二天,yazid 從2 號點出發坐車只能去往3 號節點,對回家沒有幫助。因此 yazid 只能純靠徒步回家。

對於第三天,從4 號節點出發的唯一一條邊是有積水的,車也就變得無用了。yazid只能純靠徒步回家。

對於第四天,yazid 可以坐車先到達2 號節點,再步行回家。

第五天所有的邊都積水了,因此yazid 只能純靠徒步回家。

第一天的答案是 0 ,因此第二天的 v=(5+0−1)mod5+1=5, p=(2+0)mod(3+1)=2 。

第二天的答案是 2,因此第三天的 v=(2+2−1)mod5+1=4, p=(0+2)mod(3+1)=2 。

第三天的答案是 3 ,因此第四天的 v=(4+3−1)mod5+1=2 , p=(0+3)mod(3+1)=3 。

所有測試點均保證 t≤3,所有測試點中的所有資料均滿足如下限制:

為了方便你快速理解,我們在**中使用了一些簡單易懂的表述。在此,我們對這些內容作形式化的說明:

#include#include#include#include#includeusing namespace std;

typedef long long ll;

typedef pairpr;

priority_queue,greater>kk;//dijstra堆優化

struct tree

t[15001000];

struct node

a[800100];

struct bian

}p[1001000];

ll last[500100],len,d[500001],vis[501000],tot,root[501000],fa[10100000],dep[10001000];//dep表示當前並查集深度,為了按秩合併,mn存下當前並查集哪個點到1點最近。

ll hash[501000],mn[10001000];

ll n,m,q,k,s;

ll read()

while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();

return x*flag;

}void add(ll a1,ll a2,ll a3,ll a4)

ll lastans=0;

void build(ll &node,ll l,ll r)

build(t[node].ln,l,mid);

build(t[node].rn,mid+1,r);

}ll getpos(ll node,ll l,ll r,ll x)

ll getfa(ll node,ll x)

void gai(ll &node,ll last,ll l,ll r,ll x,ll y)

t[node]=t[last];

ll mid=(l+r)/2;

if(x<=mid) gai(t[node].ln,t[last].ln,l,mid,x,y);

else gai(t[node].rn,t[last].rn,mid+1,r,x,y);

}void xiu(ll node,ll l,ll r,ll x)

ll mid=(l+r)/2;

if(x<=mid) xiu(t[node].ln,l,mid,x);

else xiu(t[node].rn,mid+1,r,x);

}ll minn(ll x,ll y)

void gai1(ll &node,ll last,ll l,ll r,ll x)

t[node]=t[last];

ll mid=(l+r)/2;

if(x<=mid) gai1(t[node].ln,t[last].ln,l,mid,x);

else gai1(t[node].rn,t[last].rn,mid+1,r,x);

}void merge(ll x,ll y,ll i)//合併並查集

void spfa()//dijkstra

); while(!kk.empty()));}

}}

}int main()

sort(p+1,p+1+m);

for(int i=1;i<=m;i++)

hash[i]=p[m-i+1].w;

q=read();k=read();s=read();

spfa();//之前spfa炸了,沒改函式名

build(root[0],1,n);

for(ll i=1;i<=m;i++)

for(ll i=1;i<=q;i++)

}return 0;

}

複雜度有點高,洛谷上最後乙個點跑3.7秒。

NOI2018 歸程 題解

容易發現,當水位線確定了,圖會被分成若干個連通塊,連通塊裡的點可以互相到達,故連通塊內點的答案為其中的點到 1 的距離的最小值,這個可以先 dijkstra 預處理求出 spfa 死了 那考慮怎麼維護連通塊。可持久化並查集?感覺不好搞,有一種神奇的演算法 kruscal 重構樹。其實就是 krusc...

NOI 2018 歸程 Kruskal重構樹

題目大意 太長了,略 kruskal重構樹,很神奇的乙個演算法吧 如果兩個並查集被某種條件合併,那麼這個條件作為乙個新的節點連線兩個並查集 那麼在接下來的提問中,如果某個點合法,它的所有子節點也都合法,即子節點的限制少於父節點 include include include include defi...

NOI2018 歸程(kruskal重構樹)

思路 每天的最短距離相當於每天走高於海拔高於水位線的路所能到達的所有點中到1的最短距離。現在要想辦法能夠直接查詢這個最短距離,如果能根據海拔構造一種樹狀結構,那麼每次能開車到達的點對應一顆子樹,那麼只需要倍增出這顆子樹的根節點就可以了。kruskal重構樹 對海拔從大到小排序,然後跑kruskal,...