您的位置:首页 > 其它

【APIO 2018】铁人两项(圆方树)

2018-07-18 08:19 330 查看

题目链接

题意大概是,求有多少三元组$(s,c,f)(s \neq c, c \neq f, s \neq f)$,满足从$s$到$f$有一条简单路径经过$c$。

得到结论:

  1. 点双中任意互不相同的三个点,必定存在一条简单路径依次经过这三个点。
  2. 显然,割点只能经过一次。

建出一棵圆方树,圆点的权值为$-1$,方点的权值为该点双中点的个数,那任意两个圆点之间可以作为它们中转点的个数就是它们在圆方树上路径的点权和。

具体来讲就是割点上只能经过一次,圆点设成$-1$是为了去重方便。

以前只写过点双缩树,这里写圆方树更方便,权且将这道题作为学习的例题吧。

建圆方树只要在Tarjan上稍作修改,这里给出建树的例子:

#include <cstdio>
#include <vector>
#include <iostream>

typedef long long LL;
const int N = 200005;

int n, m;
int dfn
, low
, in
, siz
, sta
, top, _clock, c_n;
std::vector<int> xtr
;
LL ans, sum
;

int yun = 1, las
, to[N << 1], pre[N << 1];
inline void Add(int a, int b) {
to[++yun] = b; pre[yun] = las[a]; las[a] = yun;
}

void Tarjan(int x, int fa) {
sta[++top] = x; in[x] = -1;
dfn[x] = low[x] = ++_clock;
for (int i = las[x]; i; i = pre[i]) {
if (to[i] == fa) continue;
if (dfn[to[i]]) {
low[x] = std::min(low[x], dfn[to[i]]);
} else {
Tarjan(to[i], x);
low[x] = std::min(low[x], low[to[i]]);
if (dfn[x] <= low[to[i]]) {
xtr[x].push_back(++c_n); ++in[c_n];
for (int t = -1; t != to[i]; ) {
t = sta[top--];
xtr[c_n].push_back(t); ++in[c_n];
}
}
}
}
}

void Dfs(int x) {
if (in[x] < 0) siz[x] = 1, sum[x] = in[x];
for (int i = 0; i < (int)xtr[x].size(); ++i) {
int v = xtr[x][i];
Dfs(v);
siz[x] += siz[v];
sum[x] += (LL) siz[v] * in[x] + sum[v];
}
}
void Calc(int x) {
if (in[x] < 0) ans += sum[x] - in[x];
LL cnt = 0;
for (int i = 0; i < (int)xtr[x].size(); ++i) {
int v = xtr[x][i];
ans += (LL) sum[v] * (siz[x] - (in[x] < 0) - siz[v]);
cnt += (LL) siz[v] * (siz[x] - (in[x] < 0) - siz[v]);
}
ans += (LL) cnt / 2 * in[x];
for (int i = 0; i < (int)xtr[x].size(); ++i) {
int v = xtr[x][i];
Calc(v);
}
}

int main() {
scanf("%d%d", &n, &m);
c_n = n;
for (int i = 1, x, y; i <= m; ++i) {
scanf("%d%d", &x, &y);
Add(x, y); Add(y, x);
}
for (int i = 1; i <= n; ++i) {
if (!dfn[i]) {
Tarjan(i, 0);
Dfs(i);
Calc(i);
}
}
printf("%lld\n", ans * 2);

return 0;
}
View Code

 

$\bigodot$技巧&套路:

  • 圆方树的构建,圆方树上的统计技巧,可以用圆点的权值设成$-1$来去重。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: