寫這個東西只是記錄一下我學過圓方樹 \(\text\)。
圓方樹是一種將圖變成樹的方法。
首先,把原圖中的所有點都看成圓點,我們需要求出圖中所有的點雙連通分量,可以使用 tarjan 演算法。
然後,在每乙個點雙連通分量中間建立乙個方點,將此點雙連通分量中的所有點向這個方點連邊。
這樣就可以把圖轉成樹,利用一些樹上的性質解題了。
放一張來自 wc ppt 的圖。
//headc: 原圖 head: 圓方樹
inline void add(int h, int u, int v)
void tarjan(int u)
while (y != v);
add(head, cnt, u), add(head, u, cnt);
}} else low[u] = min(low[u], dfn[v]); }}
//主函式
int main()
cnt = n;
for (int i = 1; i <= n; i+=1)
if (!dfn[i]) tarjan(i), --tp;
}圓方數上原點和方點交替出現。
圓方數的點數小於 \(2n\),因此做題時注意開兩倍空間。
圓方樹上所有不是葉子節點的圓點都是原圖中的乙個割點。
題面題意:
\(q\) 次詢問,每次詢問點 \(u\) 到點 \(v\) 所有簡單路徑的交。建出圓方樹,問題就轉換成圓方樹上點 \(u\) 與點 \(v\) 之間圓點的個數。
記錄一下樹上字首和,樹上差分即可。
**:
#include #define debug fprintf(stderr, "passing [%s] line %d\n", __function__, __line__)
#define file(x) freopen(x".in","r",stdin); freopen(x".out","w",stdout)
using namespace std;
typedef long long ll;
typedef pair pii;
typedef pair piii;
template inline t gi()
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return f * x;
}const int inf = 0x3f3f3f3f, n = 1000003, m = n << 2;
int n, m, q;
int tot, head[n], headc[n], ver[m], nxt[m];
int dfn[n], low[n], tim, stk[n], tp, cnt;
int sum[n];
inline void add(int h, int u, int v)
void tarjan(int u)
while (y != v);
add(head, cnt, u), add(head, u, cnt);
}} else low[u] = min(low[u], dfn[v]); }}
void dfs(int u, int f)
}int dep[n], fa[n], sz[n], son[n], topp[n];
void dfs1(int u, int f)
}void dfs2(int u, int f)
}inline int lca(int u, int v)
if (dep[u] < dep[v]) return u;
return v;
}int main()
cnt = n;
tarjan(1);
dfs(1, 0);
q = gi ();
dfs1(1, 0); dfs2(1, 1);
while (q--)
return 0;
}
題面
題意:
問有多少組 \(s\),\(c\) 和 \(f\),滿足存在從 \(s\) 到 \(c\) 和從 \(c\) 到 \(f\) 的簡單路徑。首先介紹乙個點雙的性質:對於乙個點雙中的兩個點 \(u\) 和 \(v\),它們之間簡單路徑的並集恰好等於這個點雙。
然後問題就轉換成了:固定 \(s\) 和 \(f\),問有多少個合法的 \(c\)。
考慮圓方樹上兩圓點在原圖中所有簡單路徑的並,將這個問題轉換到圓方樹上就變成兩圓點之間的路徑與路徑上方點所在點雙中的所有點。
這個問題很好求解,我們把圓方樹上每個方點的權值設為這個點雙中的點數,圓點的權值設為 \(-1\),答案即為圓方樹上 \(\sum\) 兩點之間所有點的權值之和。
**:
#include #define debug fprintf(stderr, "passing [%s] line %d\n", __function__, __line__)
#define file(x) freopen(x".in","r",stdin); freopen(x".out","w",stdout)
using namespace std;
typedef long long ll;
typedef pair pii;
typedef pair piii;
typedef pair pli;
template inline t gi()
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return f * x;
}const int inf = 0x3f3f3f3f, n = 200003, m = n << 3;
int n, m;
int tot, head[n], headc[n], ver[m], nxt[m];
int dfn[n], low[n], tim, stk[n], tp;
int val[n], sz[n];
int cnt;
ll ans;
int num;
inline void add(int h, int u, int v)
void tarjan(int u)
while (y != v);
add(headc, u, cnt), add(headc, cnt, u);
++val[cnt];
}} else low[u] = min(low[u], dfn[v]); }}
void dfs(int u, int f, int mn)
ans += (ll)2 * val[u] * sz[u] * (mn - sz[u]);
}int main()
for (int i = 1; i <= n * 2; i+=1) val[i] = -1;
cnt = n;
for (int i = 1; i <= n; i+=1)
if (!dfn[i])
printf("%lld\n", ans);
return 0;
}
學習筆記 圓方樹
圓方樹 元芳你怎麼看 圓方樹推薦 圓方樹是什麼?tarjan家族中,最不好處理的是點雙 因為乙個割點可能屬於很多的dcc。為了把圖縮成一棵樹,我們不得不做出這樣的處理 摘自 這個樹不但醜。而且,對於乙個點雙內部的資訊,我們把它縮成了乙個點,內部的與非割點有關的路徑我們一無所知。所以這個玩意只能用來維...
圓方樹學習筆記
聽說g2的選手都會圓方樹了,所以我來學習一波。這個階段的學習我也僅僅只是知道了圓方樹是什麼,比較簡單的題目怎麼寫,但是對於一些思維難度較高,實現能力要求較高的題目,我還不是很會.希望未來能越來越好 點雙連通分量,仙人掌的定義。點分為圓點和方點的樹.把仙人掌上的點保留,然後如果存在乙個點雙就新建乙個方...
圓方樹學習筆記
模擬賽要求圖上距離為 k 的節點對數,就學了一下圓方樹 眾所周知,樹有很多美妙的性質,但是有些題目非把樹上問題搬到圖上,這時我們就要上圓方樹了。那麼圓方樹是什麼呢?是圓形節點和方形節點構成的樹 圓方樹 block forest 或 round square tree 1就是一種將圖變成樹的方法。本文...