日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

[COCI2017-2018#5] Pictionary(并查集+dfs)

發布時間:2023/12/3 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [COCI2017-2018#5] Pictionary(并查集+dfs) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

賊ex的一道,卡了本仙女整整7個小時orz

思路容易理解,but碼力very重要orz
我愿意花五毛錢提升我的碼力,換個腦子也行,不換臉這張臉生得俊俏
luogu傳送door

題目

在宇宙一個不為人知的地方,有一個星球,上面有一個國家,只有數學家居住。 在這個國家有n個數學家,有趣的是,每個數學家都住在自己的城市,且城市間無道路相連,因為他們可以在線交流。當然,城市有從1到n的編號。

一位數學家決定用手機發論文,而手機將“不言而喻”自動更正成了“猜謎游戲”。 不久之后,這個國家就發現了猜謎游戲。他們想要見面一起玩,于是這個國家就開始了修路工程。 道路修建會持續m天。對于第i天,若gcd(a,b)=m?i+1,則a和b城市間會修一條路。

由于數學家們忙于建筑工作,請你來確定一對數學家最早什么時候能湊到一起玩。

輸入輸出格式
輸入格式
第一行有三個正整數n,m,q,表示城市數量、修路持續天數、詢問數量。 接下來q行,每行有兩個正整數a,b,表示詢問a和b兩個城市的數學家最早什么時候能在一起玩。

輸出格式
輸出q行,第i行有一個正整數,表示第i次詢問的結果

說明
數據范圍:
對于40%的數據:n≤4000,q≤10 ^5

對于全部數據:
1≤n,q≤10^5

1≤m≤n1≤m≤n

樣例1解釋: 在第一天,(3,6)(3,6)之間修了一條路,因此第二次詢問輸出1
在第二天,(2,4),(2,6),(2,8),(4,6),(6,8)(2,4),(2,6),(2,8),(4,6),(6,8)之間都修了一條路,此時44和88號城市連通,第三次詢問輸出2
在第三天,所有編號互質的城市之間都修了路,2和5號城市在此時連通,第一次詢問輸出1

樣例2解釋: 在第二天,(20,15)之間修了一條路
第四天,(15,9)之間修了一條路
所以20和9號城市在第四天連通,輸出4

題解

我看了luogu題解,發現根本沒有人跟寶寶是一個做法,當時,我的媽呀!
俺內心慌得一批,但是我在這條不歸路上繼續走了下去,誤入歧途啊
七個小時終于把這個江山打下來了
肯定很好想,問這兩個城市有沒有相通,肯定是我們的并查集大哥,這個不用多說!
而且1與任何數都互質,那么在最后一天施完工后肯定所有城市都是互通的,
這就是一棵赤裸裸的樹

我們真正要解決的就是這兩個城市在第幾天成為了一個集合

帥氣的我的實現是先預處理每一天,哪些城市會進行施工相通,邊處理,邊并查集,這樣的話就不用把所有的邊全部得到后再sort再并查集。
因為從m到1循環的話,i,j之間沒路時,這天就是最早的 ,

PS:并查集的unionSet一定要用優化的啟發式,不然就等著TLE回家找媽媽吧!
反正我是把長城都哭淹了!我們在進行unionSet時順便建個有向邊,
一定是爸爸之間建邊,又哭了orz

接著就是dfs,不一定是從1開始,可以用循環找根節點f[i]==i,哭了哭了。
dfs處理每一個點的深度,而且可以保證每個點的入度不會大于1,在處理深度的同時,把u,v兩點第幾天相同的也記錄下來,用vector可以辦到

最后就是爬樹,妙啊!妙啊!暴力lca都行的老鐵,
因為每個點都只有一個爸爸 (誒)
所以這棵樹也是唯一的,路徑唯一的,
我們就在線操作,x,y用一個Max記錄x和y在往上爬的時候路徑的最大值

以上聽起來是不是很簡單啊woo~

代碼實現

瞅瞅吧!七個小時的改了n遍,長得慘不忍睹啊!這濃縮的都是精華啊!
還有rank標記數組,rank是關鍵字,又哭了哭了orz,淚腺炸了

#include <cstdio> #include <vector> #include <iostream> using namespace std; #define MAXN 100005 #define LL long long struct node {int v, w;node () {}node ( int A, int B ) {v = A;w = B;} }depth[MAXN]; int n, m, q, cnt; int f[MAXN]; int ran[MAXN]; vector < node > tree[MAXN]; void makeSet () {for ( int i = 1;i <= n;i ++ )f[i] = i; } int findSet ( int x ) {while ( x != f[x] ) x = f[x];return x; } void unionSet ( int x, int y, int w ) {int u = findSet( x ); int v = findSet( y );if ( u == v ) return;if ( ran[u] > ran[v] ) {f[v] = u;tree[u].push_back ( node ( v, w ) );}else {f[u] = v;if( ran[u] == ran[v] )ran[v] ++;tree[v].push_back ( node ( u, w ) );} } void dfs ( int x, int dep, int val ) {if ( depth[x].v ) return;depth[x].v = dep;depth[x].w = val;for ( int i = 0;i < tree[x].size();i ++ ) {int v = tree[x][i].v, w = tree[x][i].w;dfs ( v, dep + 1, w );} } int Max = 0; void lca ( int x, int y ) {while ( depth[x].v > depth[y].v ) {Max = max ( depth[x].w, Max );x = f[x];}while ( depth[y].v > depth[x].v ) {Max = max ( depth[y].w, Max );y = f[y];}while ( x != y ) {Max = max ( depth[x].w, Max );Max = max ( depth[y].w, Max );x = f[x];y = f[y];} } int main() {scanf ( "%d %d %d", &n, &m, &q );makeSet ();for ( int i = m;i >= 1;i -- )for ( int j = i * 2;j <= n;j += i )if ( findSet ( j - i ) != findSet ( j ) )unionSet ( j - i, j, m - i + 1 );for ( int i = 1;i <= n;i ++ )if ( f[i] == i ) {dfs ( i, 1, 0 );break;}for ( int i = 1;i <= q;i ++ ) {int a, b;scanf ( "%d %d", &a, &b );Max = 0; lca ( a, b );printf ( "%d\n", Max ); }return 0; }

把這道題A(≧▽≦)/啦啦啦

好了,像打了雞血吃興奮劑一樣,有任何代碼,思路不懂得歡迎留言,歡迎歡迎熱烈歡迎,我們不賣假,誠信營業,做出世界前五百強!byebye~不要太想帥氣又多金的我!

總結

以上是生活随笔為你收集整理的[COCI2017-2018#5] Pictionary(并查集+dfs)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。