BZOJ 2001 City城市建设 (CDQ分治 + 并查集)
2018-03-03 20:41
225 查看
/** 思路: 参照 http://blog.sina.com.cn/s/blog_6e63f59e0101blum.html 主要想法就是solve(l, r)的时候, 把区间[l, r]修改的边先置为正无穷,找出一定不要的边,之后恢复状态置为负无穷,找出一定要的边,然后递归解决 solve(l, mid), solve(mid + 1, r) */ #include<bits/stdc++.h> typedef long long ll; const int maxn = 2e4 + 10; const int maxm = 5e4 + 10; const int INF = 1e9 + 10; using namespace std; struct edge { int x, y, w, pos; bool operator < (edge e) const { return w < e.w; } } e[20][maxm], d[maxm], t[maxm]; ll ans[maxm]; int n, m, q, x, y; int cost[maxm], f[maxn], mp[maxm]; int id[maxm], co[maxm]; int findset(int x) { return x == f[x] ? x : f[x] = findset(f[x]); } void init(int tot) { for(int i = 1; i <= tot; i++) f[d[i].x] = d[i].x, f[d[i].y] = d[i].y; } void delete_edge(int &tot) { int tmp = 0; init(tot); sort(d + 1, d + tot + 1); for(int i = 1; i <= tot; i++) { int nx = findset(d[i].x), ny = findset(d[i].y); if(nx != ny) { ///待选择边 f[nx] = ny; t[++tmp] = d[i]; mp[d[i].pos] = tmp; } else if(d[i].w == INF) { t[++tmp] = d[i]; mp[d[i].pos] = tmp; } } for(int i = 1; i <= tmp; i++) d[i] = t[i]; tot = tmp; } void add_edge(int &tot, ll &cnt) { int tmp = 0; init(tot); sort(d + 1, d + tot + 1); for(int i = 1; i <= tot; i++) { int nx = findset(d[i].x), ny = findset(d[i].y); if(nx != ny) { f[nx] = ny; t[++tmp] = d[i]; } } for(int i = 1; i <= tmp; i++) { f[t[i].x] = t[i].x; f[t[i].y] = t[i].y; } for(int i = 1; i <= tmp; i++) { int nx = findset(t[i].x), ny = findset(t[i].y); if(nx != ny && t[i].w != -INF) { f[nx] = ny; cnt += t[i].w; } ///必选边 } tmp = 0; for(int i = 1; i <= tot; i++) { int nx = findset(d[i].x), ny = findset(d[i].y); if(nx == ny) continue; t[++tmp] = d[i]; t[tmp].x = nx; t[tmp].y = ny; mp[d[i].pos] = tmp; ///缩点,加入待选择边,映射关系改变 } for(int i = 1; i <= tmp; i++) d[i] = t[i]; tot = tmp; } void solve(int l, int r, int tot, ll cnt, int lv) { if(l == r) cost[id[l]] = co[l]; for(int i = 1; i <= tot; i++) e[lv][i].w = cost[e[lv][i].pos]; for(int i = 1; i <= tot; i++) d[i] = e[lv][i], mp[d[i].pos] = i; ///共有tot条待选择边,修改实际第pos条边就是修改d中第i条边 if(l == r) { ans[l] = cnt; init(tot); sort(d + 1, d + tot + 1); for(int i = 1; i <= tot; i++) { int nx = findset(d[i].x), ny = findset(d[i].y); if(nx != ny) { f[nx] = ny; ans[l] += d[i].w; } } return ; } ///因为区间[L, R]是待处理区间(未确定的边), 故修改的情况一定有mp关系对应, 不用去初始化mp数组 for(int i = l; i <= r; i++) d[mp[id[i]]].w = -INF; add_edge(tot, cnt); ///处理必选边 for(int i = l; i <= r; i++) d[mp[id[i]]].w = INF; delete_edge(tot); ///处理必删边 for(int i = 1; i <= tot; i++) e[lv + 1][i] = d[i]; ///下一层分治的待选择边 int mid = (l + r) >> 1; solve(l, mid, tot, cnt, lv + 1); solve(mid + 1, r, tot, cnt, lv + 1); } int main() { while(scanf("%d 4000 %d %d", &n, &m, &q) != EOF) { for(int i = 1; i <= m; i++) { scanf("%d %d %d", &x, &y, &cost[i]); e[0][i].x = x; e[0][i].y = y; e[0][i].w = cost[i]; e[0][i].pos = i; } for(int i = 1; i <= q; i++) scanf("%d %d", &id[i], &co[i]); solve(1, q, m, 0, 0); for(int i = 1; i <= q; i++) printf("%lld\n", ans[i]); } return 0; }
相关文章推荐
- [BZOJ2001][HNOI2010]City城市建设-CDQ分治
- bzoj-2001 City 城市建设
- 【BZOJ】2001 [Hnoi2010]City 城市建设 cdq分治——动态最小生成树
- BZOJ-2001-city城市建设-HNOI2010-CDQ分治
- [动态最小生成树 CDQ分治 Kruscal] BZOJ 2001 [Hnoi2010]City 城市建设
- [bzoj2001][Hnoi2010][City 城市建设] (cdq分治)
- BZOJ2001 [Hnoi2010]City 城市建设 CDQ分治
- BZOJ2001 [Hnoi2010]City 城市建设 【CDQ分治 + kruskal】
- [动态MST] [CDQ分治] BZOJ2001: [Hnoi2010]City 城市建设
- [CDQ分治 并查集 || LCT] BZOJ 4025 二分图
- [CDQ分治 并查集] BZOJ 1453 [Wc]Dface双面棋盘
- BZOJ 3237 连通图 (cdq分治 并查集)
- BZOJ 2001 [Hnoi2010]City 城市建设 LCT+分治(未成功卡时卡过)
- BZOJ 2001([Hnoi2010]City 城市建设-CDQ重构图-动态最小生成树)
- [CDQ分治 并查集] BZOJ 3237 [Ahoi2013]连通图
- NKOJ 2936 (BZOJ 2001)城市建设(CDQ分治+LCT)
- BZOJ 2001([Hnoi2010]City 城市建设-CDQ重构图-动态最小生成树)
- bzoj 2001: City 城市建设 cdq
- BZOJ 3237 浅谈CDQ分治+带撤销并查集
- BZOJ 4025|二分图|CDQ分治|并查集|LCT