日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[BZOJ4530][Bjoi2014]大融合 LCT + 启发式合并

發布時間:2024/7/19 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [BZOJ4530][Bjoi2014]大融合 LCT + 启发式合并 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

[BZOJ4530][Bjoi2014]大融合

試題描述

小強要在N個孤立的星球上建立起一套通信系統。這套通信系統就是連接N個點的一個樹。 這個樹的邊是一條一條添加上去的。在某個時刻,一條邊的負載就是它所在的當前能夠 聯通的樹上路過它的簡單路徑的數量。 例如,在上圖中,現在一共有了5條邊。其中,(3,8)這條邊的負載是6,因 為有六條簡單路徑2-3-8,2-3-8-7,3-8,3-8-7,4-3-8,4-3-8-7路過了(3,8)。 現在,你的任務就是隨著邊的添加,動態的回答小強對于某些邊的負載的 詢問。

輸入

第一行包含兩個整數N,Q,表示星球的數量和操作的數量。星球從1開始編號。 接下來的Q行,每行是如下兩種格式之一: A x y 表示在x和y之間連一條邊。保證之前x和y是不聯通的。 Q x y 表示詢問(x,y)這條邊上的負載。保證x和y之間有一條邊。 1≤N,Q≤100000

輸出

對每個查詢操作,輸出被查詢的邊的負載。

輸入示例

8 6 A 2 3 A 3 4 A 3 8 A 8 7 A 6 5 Q 3 8

輸出示例

6

題解

LCT + 啟發式合并

我不敢直接用LCT直接維護有根樹的子樹size值,所以每次合并用啟發式合并暴力將較小的連通塊dfs重構(其實就是換根),再插到另一個連通塊中。

當樹Tree1的樹根要作為另一棵樹Tree2中節點u的兒子時,需要將Tree2中節點u到根節點的路徑上每個節點的權值加上Tree1的大小,這是一個鏈上的問題,可以用LCT解決。(代碼后附有更強的樣例)

#include <iostream> #include <cstring> #include <cstdio> #include <cmath> #include <algorithm> #include <stack> #include <vector> #include <queue> #include <cstdlib> using namespace std;const int BufferSize = 1 << 16; char buffer[BufferSize], *Head, *tail; inline char Getchar() {if(Head == tail) {int l = fread(buffer, 1, BufferSize, stdin);tail = (Head = buffer) + l;}return *Head++; } int read() {int x = 0, f = 1; char c = Getchar();while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }return x * f; }#define maxn 100010 #define maxm 200010 #define LL long long int n, q, m, head[maxn], nxt[maxm], to[maxm]; void AddEdge(int a, int b) {to[++m] = b; nxt[m] = head[a]; head[a] = m;swap(a, b);to[++m] = b; nxt[m] = head[a]; head[a] = m;return ; }int pa[maxn], siz[maxn]; int findset(int x) { return x == pa[x] ? x : pa[x] = findset(pa[x]); }int fa[maxn], ch[maxn][2], val[maxn], addv[maxn]; bool isroot(int u) { return ch[fa[u]][0] != u && ch[fa[u]][1] != u; } void pushdown(int u) {int l = ch[u][0], r = ch[u][1];if(addv[u]) {addv[l] += addv[u]; addv[r] += addv[u];val[l] += addv[u]; val[r] += addv[u];addv[u] = 0;}return ; } void maintain(int u) {return ; } void rotate(int u) {int y = fa[u], z = fa[y], l = 0, r = 1;if(ch[y][1] == u) swap(l, r);if(!isroot(y)) ch[z][ch[z][1]==y] = u;fa[u] = z; fa[y] = u; fa[ch[u][r]] = y;ch[y][l] = ch[u][r]; ch[u][r] = y;maintain(y); maintain(u);return ; } int S[maxn], top; void splay(int u) {S[++top] = u;for(int t = u; !isroot(t); t = fa[t]) S[++top] = fa[t];while(top) pushdown(S[top--]);while(!isroot(u)) {int y = fa[u], z = fa[y];if(!isroot(y)) {if((ch[y][0] == u) ^ (ch[z][0] == u)) rotate(u);else rotate(y);}rotate(u);}return ; } void access(int u) {for(int t = 0; u; u = fa[u]) {splay(u); ch[u][1] = t; maintain(u); t = u;}return ; } void add(int u, int v) {access(u); splay(u); addv[u] += v; val[u] += v;return ; } int query(int u) {access(u); splay(u);return val[u]; } void rebuild(int u) {ch[u][0] = ch[u][1] = 0;val[u] = 1;for(int e = head[u]; e; e = nxt[e]) if(to[e] != fa[u]) {fa[to[e]] = u;rebuild(to[e]);val[u] += val[to[e]];}return ; }int main() {n = read(); q = read();for(int i = 1; i <= n; i++) pa[i] = i, val[i] = siz[i] = 1;while(q--) {char tc = Getchar();while(!isalpha(tc)) tc = Getchar();int u = read(), v = read();if(tc == 'A') {int a = findset(u), b = findset(v);if(siz[a] > siz[b]) swap(a, b), swap(u, v);pa[a] = b; siz[b] += siz[a];fa[u] = v; AddEdge(u, v);rebuild(u); // printf("siz[%d] val[%d]: %d %d\n", b, u, siz[b], val[u]);add(v, siz[a]);}if(tc == 'Q') {LL x = (LL)min(query(u), query(v)); // printf("%d %d\n", query(u), query(v));printf("%lld\n", x * (siz[findset(u)] - x));}}return 0; } /* in: 8 14 A 2 3 Q 2 3 A 3 4 Q 2 3 A 3 8 Q 3 8 A 8 7 Q 3 4 A 6 5 Q 5 6 Q 3 8 A 1 6 A 1 8 Q 1 8 out: 1 2 3 4 1 6 15 */

?

轉載于:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/5392139.html

總結

以上是生活随笔為你收集整理的[BZOJ4530][Bjoi2014]大融合 LCT + 启发式合并的全部內容,希望文章能夠幫你解決所遇到的問題。

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