BZOJ 1977: [BeiJing2010组队]次小生成树 Tree( MST + 树链剖分 + RMQ )

做一次MST, 枚举不在最小生成树上的每一条边(u,v), 然后加上这条边, 删掉(u,v)上的最大边(或严格次大边), 更新答案.

树链剖分然后ST维护最大值和严格次大值..倍增也是可以的... 

------------------------------------------------------------------------------

#include<bits/stdc++.h>
 
using namespace std;
 
#define b(i) (1 << (i))
typedef long long ll;
 
const int maxn = 100009;
const int maxm = 300009;
 
inline int read() {
int ret = 0;
char c = getchar();
for(; !isdigit(c); c = getchar());
for(; isdigit(c); c = getchar())
   ret = ret * 10 + c - '0';
return ret;
}
 
ll tot = 0;
 
struct edge {
int to, w;
edge* next;
} EDGES[maxn << 1], *pt = EDGES, *head[maxn];
 
inline void add(int u, int v, int w) {
pt->to = v; pt->w = w; pt->next = head[u]; head[u] = pt++;
}
inline void addedge(int u, int v, int w) {
tot += w;
add(u, v, w); add(v, u, w);
}
 
int w[maxn], _id[maxn], N, M;
 
struct data {
int mx, _mx;
data(int _ = -1, int __ = -1):mx(_), _mx(__) {}
};
 
data make(int _, int __) {
return data(_, __);
}
 
data update(data a, data b) {
if(a.mx < b.mx)
   return data(b.mx, max(a.mx, b._mx));
else if(a.mx > b.mx)
   return data(a.mx, max(b.mx, a._mx));
else 
   return data(a.mx, max(a._mx, b._mx));
}
 
struct ST {
static const int maxlog = 20;
data mx[maxn][maxlog];
void init() {
for(int i = 0; i < N; i++) {
mx[i][0].mx = w[_id[i]];
mx[i][0]._mx = -1;
}
for(int i = 1; b(i) <= N; i++)
   for(int j = 0; j + b(i) <= N; j++)
    mx[j][i] = update(mx[j][i - 1], mx[j + b(i - 1)][i - 1]);
}
data query(int x, int y) {
int n = 0;
while(b(n) <= y - x + 1) n++; n--;
return update(mx[x][n], mx[y - b(n) + 1][n]);
}
} st;
 
struct SLPF {
static const int INF = 1000000000;
int top[maxn], size[maxn], son[maxn], dep[maxn], fa[maxn], id[maxn];
int TOP, n;
void dfs(int x) {
size[x] = 1;
son[x] = -1;
for(edge* e = head[x]; e; e = e->next) if(fa[x] != e->to) {
fa[e->to] = x;
dep[e->to] = dep[x] + 1;
w[e->to] = e->w;
dfs(e->to);
size[x] += size[e->to];
if(!~son[x] || size[son[x]] < size[e->to]) son[x] = e->to;
}
}
void DFS(int x) {
top[x] = TOP;
_id[id[x] = n++] = x;
if(~son[x]) DFS(son[x]);
for(edge* e = head[x]; e; e = e->next)
   if(e->to != son[x] && e->to != fa[x]) DFS(TOP = e->to);
}
void init() {
dep[0] = 0; fa[0] = -1;
dfs(0); DFS(n = 0);
}
data query(int x, int y) {
data ret;
for(; top[x] != top[y]; x = fa[top[x]]) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
ret = update(ret, st.query(id[top[x]], id[x]));
}
if(x == y) return ret;
if(dep[x] < dep[y]) swap(x, y);
return update(ret, st.query(id[y] + 1, id[x]));
}
} slpf;
 
struct EDGE {
int u, v, w;
bool t;
inline void Read() {
u = read() - 1;
v = read() - 1;
w = read();
t = false;
}
bool operator < (const EDGE &e) const {
return w < e.w;
}
} E[maxm];
 
struct DSU {
int p[maxn];
void init() {
for(int i = 0; i < N; i++) p[i] = i;
}
int find(int x) {
return x == p[x] ? x : p[x] = find(p[x]);
}
inline bool unite(int x, int y) {
x = find(x); y = find(y);
p[x] = y;
return x != y;
}
} dsu;
 
void MST() {
sort(E, E + M);
dsu.init();
for(int i = 0; i < M; i++) if(dsu.unite(E[i].u, E[i].v)) {
addedge(E[i].u, E[i].v, E[i].w);
E[i].t = true;
}
}
 
void init() {
scanf("%d%d", &N, &M);
for(int i = 0; i < M; i++) E[i].Read();
}
 
void work() {
slpf.init(); st.init();
ll ans = ll(1e17);
for(int i = 0; i < M; i++) if(!E[i].t) {
data h = slpf.query(E[i].u, E[i].v);
if(E[i].w == h.mx) {
if(~h._mx) ans = min(ans, tot - h._mx + E[i].w);
} else
   ans = min(ans, tot - h.mx + E[i].w);
}
printf("%lld\n", ans);
}
 
int main() {
init();
MST();
work();
return 0;
}

------------------------------------------------------------------------------ 

1977: [BeiJing2010组队]次小生成树 Tree

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 2422  Solved: 578
[Submit][Status][Discuss]

Description

小 C 最近学了很多最小生成树的算法,Prim 算法、Kurskal 算法、消圈算法等等。 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了。小 P 说,让小 C 求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说: 如果最小生成树选择的边集是 EM,严格次小生成树选择的边集是 ES,那么需要满足:(value(e) 表示边 e的权值)  这下小 C 蒙了,他找到了你,希望你帮他解决这个问题。

Input

第一行包含两个整数N 和M,表示无向图的点数与边数。 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z。

Output

包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)

Sample Input

5 6
1 2 1
1 3 2
2 4 3
3 5 4
3 4 3
4 5 6

Sample Output

11

HINT

数据中无向图无自环; 50% 的数据N≤2 000 M≤3 000; 80% 的数据N≤50 000 M≤100 000; 100% 的数据N≤100 000 M≤300 000 ,边权值非负且不超过 10^9 。

Source

 

posted @ 2015-09-15 14:28  JSZX11556  阅读(230)  评论(0编辑  收藏  举报