51 nod 1427 文明 (并查集 + 树的直径)
生活随笔
收集整理的這篇文章主要介紹了
51 nod 1427 文明 (并查集 + 树的直径)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
1427?文明
題目來源:?CodeForces
基準時間限制:1.5?秒 空間限制:131072?KB 分值:?160?難度:6級算法題安德魯在玩一個叫“文明”的游戲。大媽正在幫助他。
這個游戲里面有n個城市和m條雙向的道路。城市從1到n編號。對于每一對城市,他們之間要么有唯一的一條道路,要么就是不可互達。一條道路的定義是一個包含不同城市的序列?v1,?v2,...,vk?,??vi??和??vi+1?(1≤?i?<?k)之間有直接的一條道路相連。這條道路的長度是k-1。兩個城市在同一區域的條件是當且僅當他們之間可以互達。
在游戲過程中,會有兩個事件。
1.????安德魯問大媽,城市x所在的區域里面最長的道路是多長。
2.????安德魯要求大媽,合并城市x和城市y所在的區域。如果這兩個城市本來在同一個區域,那么就不用合并。否則合并兩個區域:從城市x所在區域選一個城市,再從城市y所在區域選一個城市,然后給這兩個城市連一條邊。選擇這兩個城市的時候要使得合并之后的區域里面最長道路盡可能小。如果有多種方案,任選一種即可。
大媽發現這些問題好難哦,所以他想請你來幫助一下。
Input 單組測試數據。 第一行包含三個整數n,m,q(1?≤?n?≤?3*10^5;?0?≤?m?<?n;?1?≤?q?≤?3*10^5),分別表示城市數目,道路數目,查詢數目。 接下來m行,每行有兩個整數?ai?和bi?(ai?≠?bi;?1?≤?ai,?bi?≤?n)。表示ai和bi之間有一條直接相連的道路。兩個城市之間最多有一條直接相連的道路。 接下來q行的格式是下列之一: 1?xi?。(1?≤?xi?≤?n)。這種情況要查詢當前xi所在的區域的最長道路。 2?xi?yi。?(1?≤?xi,?yi?≤?n)。這種情況下要求合并xi和yi所在的區域。注意:xi和yi可能是一樣的。 Output 對于第1類查詢,輸出當前區域的最長路徑長度。 Input示例 6?0?7 2?1?2 2?3?4 2?5?6 2?3?2 2?5?3 1?1 1?1 Output示例 4 4?
?
/* 51 nod 1427 文明 (并查集 + 樹的直徑)problem: 給你n個城市,m條雙向邊連接,然后是q個查詢 1 x: 城市x所在的區域的最長道路 2 x y:將兩個城市的所在區域連接,要求維護最長路最短.solve: 一個區域的最長路就相當于樹的直徑.因為兩個城市之間最多只有一條路徑. 合并的話,如果要求最短,那么相當于將兩條直徑的中點相連. 所以已知A,B的直徑可計算出新的直徑的值 (注意還要與A,B的直徑進行下比較). 先處理出每個區域的樹的直徑.然后可給每個區域打上標記,用并查集合并維護一下區域的樹的直徑.hhh-2016/09/27-17:21:09 */ #pragma comment(linker,"/STACK:124000000,124000000") #include <algorithm> #include <iostream> #include <cstdlib> #include <cstdio> #include <cstring> #include <vector> #include <map> #include <math.h> #define lson i<<1 #define rson i<<1|1 #define ll long long #define clr(a,b) memset(a,b,sizeof(a)) #define key_val ch[ch[root][1]][0] using namespace std; const int maxn = 3e5 + 100; const int inf = 0x3f3f3f3f; const ll mod = 1000000007; const double eps = 1e-7; template<class T> void read(T&num) {char CH;bool F=false;for(CH=getchar(); CH<'0'||CH>'9'; F= CH=='-',CH=getchar());for(num=0; CH>='0'&&CH<='9'; num=num*10+CH-'0',CH=getchar());F && (num=-num); } int stk[70], tp; template<class T> inline void print(T p) {if(!p){puts("0");return;}while(p) stk[++ tp] = p%10, p/=10;while(tp) putchar(stk[tp--] + '0');putchar('\n'); }struct node {int v,next; } edge[maxn << 1]; ll Max; int tot,pos; int head[maxn]; int vis[maxn]; //int ans[i]; int pre[maxn]; struct Node {ll dis;int pre; } pnode[maxn]; void init(int n) {memset(head,-1,sizeof(head));tot = 0;for(int i = 1; i <= n; i++){vis[i] = 0;pnode[i].pre = i;pnode[i].dis = 1;} } void add_edge(int u,int v) {edge[tot].v = v,edge[tot].next = head[u],head[u] = tot ++; }void dfs(int u,int fa,ll len,int anc) {vis[u] = 1;pnode[u].pre = anc;if(len > Max){Max = len;pos = u;}for(int i = head[u]; ~i; i = edge[i].next){int v = edge[i].v;if(v == fa)continue;dfs(v,u,len + 1LL,anc);} }void cal(int now) {int from;pos = 0,Max =0 ;dfs(now,-1,0,now);from = pos;pos = 0,Max = 0;dfs(from,-1,0,now);pnode[now].dis = Max; }int fin(int u) {if(pnode[u].pre != u)return pnode[u].pre = fin(pnode[u].pre);return u; }void unio(int u,int v) {int ta = fin(u);int tb = fin(v);if(ta == tb)return ;if(ta > tb)swap(ta,tb);pnode[ta].pre =tb;ll tMax = 0;tMax = max(pnode[ta].dis,pnode[tb].dis);tMax = max(tMax,(pnode[ta].dis+1LL)/2LL+(pnode[tb].dis + 1LL)/2LL + 1LL);pnode[tb].dis = tMax;pnode[ta].dis= tMax; }int main() {int n,m,q;int u,v,ob;read(n),read(m),read(q);init(n);for(int i = 1; i <= m; i++){read(u),read(v);add_edge(u,v);add_edge(v,u);}for(int i = 1;i <= n;i++){if(!vis[i])cal(i);}for(int i = 1; i <= q; i++){read(ob);if(ob == 1){read(u);int ta = fin(u);print(pnode[ta].dis);}else{read(u),read(v);unio(u,v);}}return 0; }
轉載于:https://www.cnblogs.com/Przz/p/5913697.html
總結
以上是生活随笔為你收集整理的51 nod 1427 文明 (并查集 + 树的直径)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SQLServer中ISNULL、NUL
- 下一篇: 用vue+webpack搭建的前端项目结