1. 程式人生 > >bzoj3206 [Apio2013]道路費用

bzoj3206 [Apio2013]道路費用

分享 新的 技術 sig ide 枚舉 spl 成了 urn

傳送門:http://www.lydsy.com/JudgeOnline/problem.php?id=3206

http://uoj.ac/problem/108

【題解】

我們發現可以先硬點給的邊一定選,做一遍最小生成樹,得到的其他邊就是一定選的。

然後可以縮點了,圖的大小是K。

我們枚舉選擇那些硬點的邊。

我們先把硬點的邊,加上新的連接連通塊的邊,這些邊組成了一棵樹。K+1個點K條邊。

考慮我們有一條硬點的邊,那麽對於每條有用的邊(u,v),u到v的路徑上的值都不能超過(u,v)的值(考慮kruskal過程)

然後我們暴力維護每條邊的值即可。。

你寫倍增我不攔你呀qwq

復雜度O(mlogm+2^kk^2)

技術分享
# include <stdio.h>
# include <string.h>
# include <algorithm>
// # include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int M = 5e5 + 10, N = 70;

# define RG register
# define ST static

int n, m, K;
ll ans 
= 0; struct edge{ int u, v, w; friend bool operator < (edge a, edge b) { return a.w < b.w; } }a[M], b[N], e[M]; int en = 0; ll v[M], sum[M]; bool ok[M]; int res[M], resn = 0, S; struct unionset { int fa[M]; inline void set() { for (int i=1; i<=n; ++i) fa[i] = i; } inline
int getf(int x) { return fa[x] == x ? x : fa[x] = getf(fa[x]); } }A, B; int fa[M], mi[M], dep[M]; int head[M], nxt[M], to[M], tot; inline void add(int u, int v) { ++tot; nxt[tot] = head[u]; head[u] = tot; to[tot] = v; } inline void adde(int u, int v) { add(u, v), add(v, u); } inline void dfs(int x, int fat = 0) { fa[x] = fat; dep[x] = dep[fat] + 1; sum[x] = v[x]; for (int i=head[x]; i; i=nxt[i]) { if(to[i] == fat) continue; dfs(to[i], x); sum[x] += sum[to[i]]; } } inline void solve(int sta) { tot = 0; // printf("status = %d\n", sta); for (int i=1; i<=resn; ++i) { int x = res[i]; head[x] = 0; A.fa[x] = x; fa[x] = 0; mi[x] = 1e9; } for (int i=1; i<=K; ++i) if(sta & (1<<(i-1))) ok[i] = 1; else ok[i] = 0; for (int i=1; i<=K; ++i) if(ok[i]) { int u = A.getf(b[i].u), v = A.getf(b[i].v); if(u == v) return ; // A.fa[u] = v; adde(b[i].u, b[i].v); } for (int i=1; i<=en; ++i) { int u = A.getf(e[i].u), v = A.getf(e[i].v); if(u == v) continue; A.fa[u] = v; adde(e[i].u, e[i].v); } dfs(S); for (int i=1; i<=en; ++i) { int u = e[i].u, v = e[i].v; if(dep[u] < dep[v]) swap(u, v); while(dep[u] != dep[v]) { mi[u] = min(mi[u], e[i].w); u = fa[u]; } while(u != v) { mi[u] = min(mi[u], e[i].w); mi[v] = min(mi[v], e[i].w); u = fa[u], v = fa[v]; } } ll cur = 0; for (int i=1; i<=K; ++i) { if(ok[i]) { int u = b[i].u, v = b[i].v; if(dep[u] < dep[v]) swap(u, v); cur += sum[u] * mi[u]; } } if(cur > ans) ans = cur; } int main() { scanf("%d%d%d", &n, &m, &K); A.set(), B.set(); for (int i=1; i<=m; ++i) scanf("%d%d%d", &a[i].u, &a[i].v, &a[i].w); sort(a+1, a+m+1); for (int i=1; i<=K; ++i) { scanf("%d%d", &b[i].u, &b[i].v); int u = A.getf(b[i].u), v = A.getf(b[i].v); A.fa[u] = v; } for (int i=1; i<=m; ++i) { int u = A.getf(a[i].u), v = A.getf(a[i].v); if(u != v) { A.fa[u] = v; u = B.getf(a[i].u), v = B.getf(a[i].v); B.fa[u] = v; } } S = B.getf(1); for (int i=1, t; i<=n; ++i) { scanf("%d", &t); v[B.getf(i)] += t; if(B.getf(i) == i) res[++resn] = i; } for (int i=1; i<=K; ++i) { b[i].u = B.getf(b[i].u); b[i].v = B.getf(b[i].v); } for (int i=1; i<=m; ++i) { // printf("====%d, %d\n", a[i].u, a[i].v); a[i].u = B.getf(a[i].u); a[i].v = B.getf(a[i].v); // printf("modified %d, %d\n", a[i].u, a[i].v); } for (int i=1; i<=m; ++i) { int u = B.getf(a[i].u), v = B.getf(a[i].v); if(u != v) ok[i] = 1, B.fa[u] = v; else ok[i] = 0; } for (int i=1; i<=m; ++i) if(ok[i]) e[++en] = a[i]; for (int sta=0; sta < (1<<K); ++sta) solve(sta); printf("%lld\n", ans); return 0; }
View Code

bzoj3206 [Apio2013]道路費用