- https://oi-wiki.org/graph/block-forest/#%E4%BE%8B%E9%A2%98
- https://codeforces.com/gym/102512/problem/A
- https://www.shuizilong.com/house/archives/spoj-9577-dynamic-tree-connectivity/
- https://www.shuizilong.com/house/archives/spoj-375-query-on-a-tree/
仙人掌
LibreOJ #2587. 「APIO2018」铁人两项
巧妙的标号,设方点的权值为周围圆点的个数,圆点的权值为 -1,那么任意一个合法的 (s,f),中间合法的 c 恰好等于它们在圆方树上路径的权值和。于是直接树 dp 即可。
Codeforces Round 278 (Div. 1) E. Tourists
圆方树后转化为 QTREE。
如果我们方点的权值记为所有周围圆点的最小值,那么修改圆点操作可能会影响 O(n) 个节点,
但是其实我们可以只考虑有根树,方点只记录孩子中圆点的最小值,那么操作就只会影响 O(1) 个节点了,
这样统计答案的时候,如果 lca 是方点,只要再向上取一个最小值即可。
这个技巧在 之前 也出现过。
Luogu P8456. 「SWTR-8」地地铁铁
难点在于什么情况下两点之间同时存在白路径和黑路径,但不存在黑白路径。
这个题还需要找到每个双连通分量内的所有边,所以还需要开个边栈。
#include <lastweapon/io>
using namespace lastweapon;
const int N = int(1e6) + 9, M = int(2e6) + 9;
int dfn[N], low[N]; stack<int> sta, sta_e; int nn;
int hd[N], suc[M], to[M];
int n; LL z;
namespace DSU{ // Disjoint Set Union
int P[N], R[N], sz[N];
inline void Make(int x){
P[x] = x, R[x] = 0;
}
inline int Find(int x){
return P[x] == x ? x : P[x] = Find(P[x]);
}
inline void Unionn(int x, int y){
if (R[x] == R[y]) ++R[x];
else if (R[x] < R[y]) swap(x, y);
sz[x] += sz[y];
P[y] = x;
}
inline void Union(int x, int y){
x = Find(x), y = Find(y);
if (x != y) Unionn(x, y);
}
} //using namespace DSU;
inline LL C2(LL n) {
return n*(n-1)/2;
}
struct Block_Cut_Tree {
VI adj[N]; int fa[N], col[N];
int n;
void add_block(int u, int v, int r) {
++n; int b = ::n+n;
adj[u].PB(b); fa[b] = u;
do {
u = sta.top(); sta.pop();
adj[b].PB(u);
} while (u^v);
int i, c; map<int, int> mask;
do {
i = sta_e.top(), sta_e.pop();
u = to[i^1], v = to[i]; if (u < 0) u = -u, v = -v, c = 2; else c = 1;
col[b] |= c; mask[u] |= c; mask[v] |= c;
} while (r^i);
if (col[b] == 3) {
int cnt = 0; for (auto t: mask) if (t.se == 3) {
if (++cnt > 2) break;
}
if (cnt == 2) --z;
}
}
LL calc(int c) {
using namespace DSU;
int nn = ::n+n;
REP_1(i, nn) Make(i);
REP_1(i, ::n) sz[i] = 1;
REP_1(i, n) sz[::n+i] = 0;
FOR_1(b, ::n+1, nn) if (col[b] == c) {
Union(b, fa[b]);
for (auto u: adj[b]) Union(b, u);
}
LL z = 0; REP_1(i, nn) if (Find(i) == i) z += C2(sz[i]);
return z;
}
} bct;
void tarjan(int u = 1, int r = 0) {
dfn[u] = low[u] = ++nn;
sta.push(u);
REP_G(i, u) if (i^r) {
int v = abs(to[i]);
if (dfn[v]) {
if (dfn[u] < dfn[v]) continue;
sta_e.push(i);
checkMin(low[u], dfn[v]);
} else {
sta_e.push(i); tarjan(v, i^1);
checkMin(low[u], low[v]);
if (dfn[u] <= low[v]) { // find a cut!
bct.add_block(u, v, i);
}
}
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
//freopen("/Users/minakokojima/Documents/GitHub/ACM-Training/Workspace/out.txt", "w", stdout);
#endif
RD(); int m; RD(n, m);
for (int i=2;i<=2*m;) {
int x, y; bool c; RD(x, y); c = RC() == 'd';
suc[i] = hd[x], hd[x] = i, to[i] = c ? -y : y; ++i;
suc[i] = hd[y], hd[y] = i, to[i] = c ? -x : x; ++i;
}
z = C2(n); tarjan();
z -= bct.calc(1) + bct.calc(2);
cout << z << endl;
}




Alca
Amber
Belleve Invis
Chensiting123
Edward_mj
Fotile96
Hlworld
Kuangbin
Liyaos
Lwins
LYPenny
Mato 完整版
Mikeni2006
Mzry
Nagatsuki
Neko13
Oneplus
Rukata
Seter
Sevenkplus
Sevenzero
Shirleycrow
Vfleaking
wangzhpp
Watashi
WJMZBMR
Wywcgs
XadillaX
Yangzhe
三途川玉子
About.me
Vijos
