离家出走时间限制: 2000 ms 内存限制: 256M 【题目描述】企鹅豆豆考试爆零了 心态爆炸的他准备离家出走 贫穷的企鹅国有 N 座城市 一开始城市之间没有道路连接不能通行 随着时间推移,一些道路逐渐建立 但由于国家财力实在不足 所以随时随地任意两座城市最多只有一条路径可以互相到达 每次豆豆考试爆炸,他都想从考场里跑到离考场最远的一个城市去 当然豆豆每次都会想知道 最远的且可以到达的城市离考场所在城市有多远? 奇妙的事情是,企鹅国的每一条道路长度都是 1 【输入】第一行一个整数 type,表示数据类型。 接下来第二行两个整数 N,Q,表示城市个数和事件个数。 接下来 Q 行,先读入一个整数 op,表示事件类型。 如果 op=1,那么接着有两个整数 u,v 表示城市 u 和城市 v 之间建立了一条新的道路。 如果 op=2,那么接着有一个整数 u 表示这次考试的考场在城市 u 豆豆想知道最远的城市离考场有多远。 如果 type=1,令上一次 op=2 时的答案为 lastans, 那么对于输入的每一个 u 或者 v 都需要异或上 lastans (lastans 初始为 0。) 如果 type=0,那么不需要进行其余额外操作。 【输出】对于每次 op=2 的询问 输出一行一个整数表示离考场最远的城市距离考场的距离。 【输入样例】0
5 10
1 4 5
2 3
2 5
2 1
1 5 3
1 1 4
2 3
2 5
1 5 2
2 1
【输出样例】0
1
0
3
2
3
【提示】对于 20%的输入数据:N≤5000,Q≤10000。 对于 50%的输入数据:N≤100000,Q≤200000。 对于另外 20%的输入数据:type=0。 对 100%的输入数据:N≤300000,Q≤500000, 道路的修建会满足,随时随地图中不存在环。 |
毒瘤...
反正就是个并查集 + 倍增lca + 启发式合并,复杂度Qlog²n
有个性质:合并两个树,新的直径端点一定在原直径端点上。
还有个:树上一点能到达的最远点一定是直径端点
然后合并的时候启发式合并,更新小树上的dis,fa
同时更新大树根上记录的直径端点。
A了但是这数据有毒,暴力合并比正解还快...没有一条链数据来卡。
1 #include <cstdio> 2 #include <algorithm> 3 const int N = 400010; 4 5 struct Edge { 6 int v, nex; 7 }edge[N << 1]; int top; 8 int dis[N], siz[N], fa[N][20], l[N], r[N], e[N]; 9 int ufs[N], lm; 10 inline void init(const int &n) { 11 lm = 19; 12 while((1 << lm) > n) { 13 lm--; 14 } 15 for(int i = 1; i <= n; i++) { 16 ufs[i] = i; 17 siz[i] = 1; 18 dis[i] = 1; /// error : 0 19 l[i] = r[i] = i; /// error : i 20 } 21 return; 22 } 23 inline void add(int x, int y) { 24 top++; 25 edge[top].v = y; 26 edge[top].nex = e[x]; 27 e[x] = top; 28 return; 29 } 30 inline int find(int x) { 31 if(ufs[x] == x) { 32 return x; 33 } 34 return ufs[x] = find(ufs[x]); 35 } 36 void DFS(int x, int d, int f) { /// error : NO f 37 dis[x] = d; 38 for(int i = 1; i <= lm; i++) { 39 fa[x][i] = fa[fa[x][i - 1]][i - 1]; 40 } 41 for(int i = e[x]; i; i = edge[i].nex) { 42 int y = edge[i].v; 43 if(y == f) { 44 continue; 45 } 46 fa[y][0] = x; 47 DFS(y, d + 1, x); 48 } 49 return; 50 } 51 inline int lca(int x, int y) { 52 if(dis[x] > dis[y]) { 53 std::swap(x, y); 54 } 55 int i = lm; 56 while(i >= 0 && dis[x] != dis[y]) { 57 if(dis[x] <= dis[fa[y][i]]) { 58 y = fa[y][i]; 59 } 60 i--; 61 } 62 if(x == y) { 63 return x; 64 } 65 i = lm; 66 while(i >= 0 && fa[x][0] != fa[y][0]) { 67 if(fa[x][i] != fa[y][i]) { 68 x = fa[x][i]; 69 y = fa[y][i]; 70 } 71 i--; 72 } 73 return fa[x][0]; 74 } 75 inline int dist(int x, int y) { 76 return dis[x] + dis[y] - (dis[lca(x, y)] << 1); 77 } 78 inline void merge(int x, int y) { 79 int tx = find(x); 80 int ty = find(y); 81 if(siz[tx] < siz[ty]) { 82 std::swap(x, y); 83 std::swap(tx, ty); 84 } 85 /// x >= y 86 fa[y][0] = x; 87 DFS(y, dis[x] + 1, x); 88 siz[tx] += siz[ty]; 89 90 int A = l[tx], B = l[ty]; 91 int C = r[tx], D = r[ty]; 92 int len = dist(A, C); 93 int a = A, b = C; 94 int t = dist(A, B); 95 if(len < t) { 96 len = t; 97 b = B; 98 } 99 t = dist(A, D); 100 if(len < t) { 101 len = t; 102 b = D; 103 } 104 t = dist(C, B); 105 if(len < t) { 106 len = t; 107 a = C; 108 b = B; 109 } 110 t = dist(B, D); 111 if(len < t) { 112 len = t; 113 a = B; 114 b = D; 115 } 116 t = dist(C, D); 117 if(len < t) { 118 a = C; 119 b = D; 120 } 121 l[tx] = a; 122 r[tx] = b; 123 add(x, y); 124 add(y, x); 125 ufs[ty] = tx; 126 return; 127 } 128 inline int ask(int x) { 129 int L = l[find(x)], R = r[find(x)]; 130 return std::max(dist(x, L), dist(x, R)); 131 } 132 int main() { 133 int k; 134 int n, T; 135 scanf("%d", &k); 136 scanf("%d%d", &n, &T); 137 init(n); 138 int f, x, y, lastans = 0; 139 while(T--) { 140 scanf("%d", &f); 141 if(f == 1) { 142 scanf("%d%d", &x, &y); 143 if(k) { 144 x ^= lastans; 145 y ^= lastans; 146 } 147 if(find(x) != find(y)) { 148 merge(x, y); 149 } 150 } 151 else { 152 scanf("%d", &x); 153 if(k) { 154 x ^= lastans; 155 } 156 lastans = ask(x); 157 printf("%d ", lastans); 158 } 159 } 160 return 0; 161 }