1. 程式人生 > >10.3 (2) 到不了

10.3 (2) 到不了

Description wy  和  wjk  是好朋友。 今天他們在一起聊天,突然聊到了以前一起唱過的《到不了》。 “說到到不了,我給你講一個故事吧。” “嗯?” “從前,神和凡人相愛了,憤怒的神王把他們關進了一個迷宮裡,迷宮是由許多棵有根樹組 成的。神王每次把兩個人扔進其中的某一棵有根樹裡面,兩個相鄰節點的距離為  1,兩人的 每一步都只能從兒子走到父親,不能從父親走到兒子,他們約定,走到同一個節點相見,由 於在迷宮裡面行走十分消耗體力,他們決定找出那個使得他們走的總路程最少的節點,他們 當然會算出那個節點了,可是神王有時候會把兩棵有根樹合併為一棵,這下就麻煩了。。。” “唔。。。” [已經瞭解樹,森林的相關概念的同學請跳過下面一段] 樹:由  n  個點,n-1  條邊組成的無向連通圖。 父親/兒子:把樹的邊距離定義為  1,root  是樹的根,對於一棵樹裡面相鄰的兩個點  u,v,到 root 的距離近的那個點是父親,到  root  距離遠的那個點是兒子 森林:由若干棵樹組成的圖 [簡化版題目描述] 維護一個森林,支援連邊操作和查詢兩點  LCA  操作 Input 第一行一個整數  N,M,代表森林裡的節點總數和有根樹的數目。 第二行  M  個整數,第  i  個整數  ri  代表第  i  棵有根樹的根是編號為  ri  的節點 接下來  N-M  行,每行兩個整數  u,v  表示  u  和  v  相鄰 接下來一行一個整數  Q,表示  Q  個事件發生了

接下來  Q  行,每行若干個整數,表示一個事件 如果第一個數  op=1,接下來兩個整數  u,v,代表神王把  u  號節點所在的樹和  v  號節點所在 的樹合併到一起(即  u  到  v  連了一條邊),新的根為原來  u  號節點所在的樹的根(如果  u,v  已經聯通,忽略這個事件)。 如果第一個數  op=2,接下來兩個整數  u,v,代表一次詢問,當一個人在  u  號節點,一個 人在  v  號節點,詢問他們找到的那個節點的編號 Output  對於每一個詢問(op=2  的操作),輸出一行一個整數,代表節點編號,如果  u,v  不聯通, 輸  出  orzorz。  Sample Input  【樣例  1】 2 2  1 2  2  1 1 2 2 1 2  【樣例  2】  2 2  1 2  2  1 2 1  2 1 2  Sample Output  【樣例  1】  1  【樣例  2】  2 Hint  【資料範圍】  對於  30%的資料  1 ≤ N ≤ 1000 1 ≤ Q ≤ 1000  對於  100%的資料  1 ≤ N ≤ 100000 1 ≤ Q ≤ 100000

題解:啟發式合併兩棵樹的  LCA  倍增陣列,每次總是把節點數少的那棵樹合併到節點多的那棵樹上

重新建立連邊的那一可樹,找距離時即從深度比較深的lca入手

#include<bits/stdc++.h> using namespace std; #define ll long long #define out(x) print(x) const int MAXN = 1e5 + 5; int f[MAXN][21]; int dep[MAXN],rt[MAXN],root[MAXN]; int size[MAXN]; int head[MAXN*2],cnt = 0;

struct node {     int next,to;      } e[MAXN*2];

void add(int u,int v) {          e[++cnt].next = head[u],e[cnt].to = v,head[u] = cnt;     e[++cnt].next = head[v],e[cnt].to = u,head[v] = cnt;      } int n,m,q,E;

void rebuild(int x,int fr) {          for(int i = 1; i <= 20; i++) f[x][i] = f[f[x][i-1]][i-1];          for(int i = head[x]; i; i = e[i].next) {         int to = e[i].to;         if(to == fr) continue;         dep[to] = dep[x] + 1;         f[to][0] = x;         rebuild(to,x);     } }

void dfs(int x,int fr) {          f[x][0] = fr;          for(int i = head[x]; i; i = e[i].next) {                  int to = e[i].to;         if(to == fr) continue;         dep[to] = dep[x] + 1;         dfs(to,x);         size[x] += size[to];     } }

int get(int x) {          for(int i = 20; i >= 0; i--) if(f[x][i]) x = f[x][i];     return x;      }

int lca(int x,int y) {          if(dep[x] < dep[y]) swap(x,y);          for(int i = 20; i >= 0; i--)         if(dep[x] - (1 << i) >= dep[y])             x = f[x][i];                  if(x == y) return x;          for(int i = 20; i >= 0; i--)         if(f[x][i] != f[y][i])             x = f[x][i],y = f[y][i];                  return f[x][0]; }

int main() {          cin>>n>>m;     for(int i = 1; i <= m; i++) cin>>rt[i];     int e;     cin>>e;          for(int i = 1; i <= n-m; i++) {         int x,y;         cin>>x>>y;         add(x,y);     }          for(int i = 1; i <= n; i++) size[i] = 1;          for(int i = 1; i <= m; i++) {         dep[rt[i]] = 1;         dfs(rt[i],0);     }          for(int j = 1; j <= 20; j++)         for(int i = 1; i <= n; i++)             f[i][j] = f[f[i][j-1]][j-1];                  for(int i = 1; i <= n; i++) {         int o = get(i);                  if(o) root[i] = o;         else root[i] = i;     }          cin>>q;          for(int i = 1; i <= q; i++) {         int o,u,v;         cin>>o>>u>>v;                  if(o == 1) {             int x = get(u),y = get(v);             if(x == y) continue;             if(size[x] > size[y]) {                 f[v][0] = u;                 size[x] += size[y];                 dep[v] = dep[u] + 1;                 root[y] = root[x];                 add(u,v);                 rebuild(v,u);             }             else {                 f[u][0] = v;                 size[y] += size[x];                 dep[u] = dep[v] + 1;                 root[y] = root[x];                 add(u,v);                 rebuild(u,v);             }         } else {             int a = u;             int b = v;             if(get(a) != get(b)) {                 cout << "orzorz" << endl;                 continue;             }              else {                 int c = get(a);                                  int a = lca(u,v);                                  int b = lca(root[c],v);                                  if(dep[a] < dep[b]) a = b;                 b = lca(root[c],u);                                  if(dep[a] < dep[b]) a = b;                 cout<<a<<endl;             }         }     }     return 0; }