您的位置:首页 > 其它

BZOJ3206 [Apio2013]道路费用

2015-05-08 22:38 405 查看
首先我们强制要求几条待定价的边在MST中,建出MST

我们发现这个MST中原来的边是一定要被选上的,所以可以把点缩起来,搞成一棵只有$K$个点的树

然后$2^K$枚举每条边在不在最终的MST中,让在最终MST中的待定价的边尽量大,只需要在Kruskal的时候暴力更新每条边的定价即可

时间复杂度$O(m * logm + 2^K * K^2)$

/**************************************************************
Problem: 3206
User: rausen
Language: C++
Result: Accepted
Time:8040 ms
Memory:8232 kb
****************************************************************/

#include <cstdio>
#include <algorithm>

using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
const int M = 3e5 + 5;
const int K = 25;
const int inf = 1e9;

inline int read();

struct Edge {
int x, y, v;

inline void get(int f) {
x = read(), y = read();
if (f) v = read();
}

inline bool operator < (const Edge &E) const {
return v < E.v;
}
} E[M], Ek[K], s[K];

struct edge {
int next, to;
edge() {}
edge(int _n, int _t) : next(_n), to(_t) {}
} e[K << 1];

int first
, tot;

struct tree_node {
int fa, dep, mn;
ll v, sum;
} tr
;

int n, m, k, S, top;
int fa[2]
;
int root[K], cnt_root;
int u[K];
ll ans;

inline void Add_Edges(int x, int y) {
e[++tot] = edge(first[x], y), first[x] = tot;
e[++tot] = edge(first[y], x), first[y] = tot;
}

int find(int x, int f) {
return x == fa[f][x] ? x : fa[f][x] = find(fa[f][x], f);
}

#define y e[x].to
void dp(int p) {
int x;
tr[p].sum = tr[p].v;
for (x = first[p]; x; x = e[x].next)
if (y != tr[p].fa) {
tr[y].dep = tr[p].dep + 1, tr[y].fa = p;
dp(y);
tr[p].sum += tr[y].sum;
}
}
#undef y

ll work() {
static int i, x, y, p;
static ll res;
for (tot = 0, i = 1; i <= k + 1; ++i) {
p = root[i];
fa[0][p] = p;
first[p] = tr[p].fa = 0, tr[p].mn = inf;
}
for (i = 1; i <= k; ++i)
if (u[i]) {
x = find(Ek[i].x, 0), y = find(Ek[i].y, 0);
if (x == y) return 0;
fa[0][x] = y;
Add_Edges(Ek[i].x, Ek[i].y);
}
for (i = 1; i <= k; ++i) {
x = find(s[i].x, 0), y = find(s[i].y, 0);
if (x != y) fa[0][x] = y, Add_Edges(s[i].x, s[i].y);
}
dp(S);
for (i = 1; i <= k; ++i) {
x = s[i].x, y = s[i].y;
if (tr[x].dep < tr[y].dep) swap(x, y);
while (tr[x].dep != tr[y].dep)
tr[x].mn = min(tr[x].mn, s[i].v), x = tr[x].fa;
while (x != y) {
tr[x].mn = min(tr[x].mn, s[i].v);
tr[y].mn = min(tr[y].mn, s[i].v);
x = tr[x].fa, y = tr[y].fa;
}
}
#define x Ek[i].x
#define y Ek[i].y
for (res = 0, i = 1; i <= k; ++i)
if (u[i])
res += tr[x].dep > tr[y].dep ? tr[x].mn * tr[x].sum : tr[y].mn * tr[y].sum;
#undef x
#undef y
return res;
}

void dfs(int p) {
if (p == k + 1) {
ans = max(ans, work());
return;
}
u[p] = 0, dfs(p + 1);
u[p] = 1, dfs(p + 1);
}

int main() {
int i, x, y;
n = read(), m = read(), k = read();
for (i = 1; i <= m; ++i) E[i].get(1);
for (i = 1; i <= k; ++i) Ek[i].get(0);
for (i = 1; i <= n; ++i) tr[i].v = read();
sort(E + 1, E + m + 1);
for (i = 1; i <= n; ++i) fa[0][i] = fa[1][i] = i;

for (i = 1; i <= k; ++i)
fa[0][find(Ek[i].x, 0)] = find(Ek[i].y, 0);
#define x E[i].x
#define y E[i].y
for (i = 1; i <= m; ++i)
if (find(x, 0) != find(y, 0))
fa[0][find(x, 0)] = fa[0][find(y, 0)], fa[1][find(x, 1)] = fa[1][find(y, 1)];
#undef x
#undef y
S = find(1, 1);
for (i = 1; i <= n; ++i)
if (find(i, 1) != i) tr[find(i, 1)].v += tr[i].v;
else root[++cnt_root] = i;
#define x Ek[i].x
#define y Ek[i].y
for (i = 1; i <= k; ++i)
x = find(x, 1), y = find(y, 1);
#undef x
#undef y
#define x E[i].x
#define y E[i].y
for (i = 1; i <= m; ++i)
x = find(x, 1), y = find(y, 1);
for (i = 1; i <= m; ++i)
if (find(x, 1) != find(y, 1))
s[++top] = E[i], fa[1][find(x, 1)] = find(y, 1);
#undef x
#undef y
dfs(1);
printf("%lld\n", ans);
return 0;
}

inline int read() {
static int x;
static char ch;
x = 0, ch = getchar();
while (ch < '0' || '9' < ch)
ch = getchar();
while ('0' <= ch && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
}
return x;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: