• [PA2014]Fiolki


    Description

    BZOJ3712
    有n个瓶子装着n种物质,有k个反应,每个反应表示1g(a)和1g(b)反应生成2g沉淀,反应优先级为给定顺序,有m个操作形如将瓶子a中的物质倒入瓶子b中(保证a,b非空)。求最后生成的沉淀。

    Solution

    容易看出操作构成了一棵树,那么,把操作看成连边的话,某个反应发生的时间就是参与该反应的两种物质联通的时间!重构树!
    按着这个思路,用操作建出重构树,把反应按着重构树上的LCA深度和反应优先级排序就行了,不要忘记反应优先级也是有用的。

    Code

    #include <cstdio>
    #include <algorithm>
    #include <vector>
    
    const int N = 200010 * 2;
    const int M = 500000 + 10;
    const int INF = 0x3f3f3f3f;
    
    std::vector<int> g[N];
    int fa[N], tot, n, m, k, w[N];
    int sz[N], son[N], dep[N], top[N], pa[N];
    struct Reaction {
    	int a, b, tim, id;
    	bool operator<(const Reaction& x) const {
    		return tim == x.tim ? id < x.id : tim > x.tim;
    	}
    } rct[M];
    
    int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
    
    int merge(int x, int y) {
    	int fx = find(x), fy = find(y);
    	if (fx == fy) return -1;
    	tot++;
    	g[tot].push_back(fx);
    	g[tot].push_back(fy);
    	fa[fx] = fa[fy] = fa[tot] = tot;
    	return 0;
    }
    
    void dfs(int x, int f) {
    	dep[x] = dep[f]+1;
    	pa[x] = f;
    	sz[x] = 1;
    	for (unsigned int i = 0; i < g[x].size(); ++i) {
    		dfs(g[x][i], x);
    		sz[x] += sz[g[x][i]];
    		if (sz[g[x][i]] > sz[son[x]]) son[x] = g[x][i];
    	}
    }
    
    void rebuild(int x, int f) {
    	top[x] = f;
    	if (son[x]) rebuild(son[x], f);
    	for (unsigned int i = 0; i < g[x].size(); ++i) if (g[x][i] != son[x]) {
    		rebuild(g[x][i], g[x][i]);
    	}
    }
    
    int lca(int x, int y) {
    	if (find(x) != find(y)) return -INF;
    	while (top[x] != top[y]) {
    		if (dep[top[x]] < dep[top[y]]) y = pa[top[y]];
    		else x = pa[top[x]];
    	}
    	return dep[x] < dep[y] ? dep[x] : dep[y];
    }
    
    int main() {
    	scanf("%d%d%d", &n, &m, &k);
    	for (int i = 1; i <= n; ++i) {
    		scanf("%d", &w[i]);
    		fa[i] = i;
    	}
    	tot = n;
    	for (int i = 1, x, y; i <= m; ++i) {
    		scanf("%d%d", &x, &y);
    		merge(x, y);
    	}
    	for (int i = tot; i; --i) if (!sz[i]) {
    		dfs(i, 0);
    		rebuild(i, i);
    	}
    	for (int i = 1; i <= k; ++i) {
    		scanf("%d%d", &rct[i].a, &rct[i].b);
    		rct[i].tim = lca(rct[i].a, rct[i].b);
    		rct[i].id = i;
    	}
    	std::sort(rct+1, rct+k+1);
    	long long ans = 0;
    	for (int i = 1; i <= k; ++i) {
    		if (rct[i].tim == -INF) break;
    		long long s = std::min(w[rct[i].a], w[rct[i].b]);
    		ans += s * 2LL;
    		w[rct[i].a] -= s;
    		w[rct[i].b] -= s;
    	}
    	printf("%lld
    ", ans);
    	return 0;
    }
    

    Note

    关于反应优先级的问题,这有一个栗子:四种物质,分别为(8g, 4g, 2g, 2g),反应为(1+2,2+3,3+4),操作是(1-4, 2-3, 3-4),可以看出,如果不规定反应顺序的话,反应的结果可能有多个。

  • 相关阅读:
    Android编译系统
    Android指针管理:RefBase,SP,WP
    Android图片异步加载
    Android动画学习笔记Android Animation
    触发checkbox的click事件时遇到的问题
    C++ Primer笔记
    Android自定义对话框(Dialog)位置,大小
    android startService流程梳理笔记
    自定义SimpleAdapter
    Android Touch事件
  • 原文地址:https://www.cnblogs.com/wyxwyx/p/bzoj3712.html
Copyright © 2020-2023  润新知