【BZOJ】3712: [PA2014]Fiolki

http://www.lydsy.com/JudgeOnline/problem.php?id=3712

题意:n个瓶子,第i个瓶子里又g[i]克物质。m次操作,第i次操作把第a[i]个瓶子的东西全部倒到第b[i]个瓶子里(保证之后不出现a[i])。k种反应,其中c[i]和d[i]反应,而且如果一个瓶子里有多种反应则优先反应靠前的。每次反应对答案贡献为min(g[i], g[i])*2(m<n<=200000, k<=500000)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=200005, M=200005, nQ=500005;
ll ans;
int n, m, K, ihead[N+M], cnt, pos[N], g[N], dep[N+M], f[N+M][20], tot;
struct E { int next, to; } e[(N+M)<<1];
struct Q { int x, y, ff, dep, id; } q[nQ];
bool cmp(const Q &a, const Q &b) {
	return a.dep==b.dep?a.id<b.id:a.dep>b.dep;
}
void add(int x, int y) {
	e[++cnt]=(E){ihead[x], y}; ihead[x]=cnt;
	e[++cnt]=(E){ihead[y], x}; ihead[y]=cnt;
}
void dfs(int x) {
	for(int i=1; i<=19; ++i) f[x][i]=f[f[x][i-1]][i-1];
	for(int i=ihead[x]; i; i=e[i].next) if(e[i].to!=f[x][0]) { f[e[i].to][0]=x; dep[e[i].to]=dep[x]+1; dfs(e[i].to); }
}
int lca(int x, int y) {
	if(dep[x]<dep[y]) swap(x, y);
	int d=dep[x]-dep[y];
	for(int i=19; i>=0; --i) if((d>>i)&1) x=f[x][i];
	if(x==y) return x;
	for(int i=19; i>=0; --i) if(f[x][i]!=f[y][i]) x=f[x][i], y=f[y][i];
	return f[x][0];
}
int main() {
	scanf("%d%d%d", &n, &m, &K);
	for(int i=1; i<=n; ++i) pos[i]=i;
	for(int i=1; i<=n; ++i) scanf("%d", &g[i]);
	for(int i=1; i<=m; ++i) { int a, b; scanf("%d%d", &a, &b); int ff=n+i; add(pos[a], ff); add(pos[b], ff); pos[b]=ff; }
	for(int i=n+m; i>=1; --i) if(!f[i][0]) dfs(i);
	for(int i=1; i<=K; ++i) { int a, b, ff; scanf("%d%d", &a, &b); ff=lca(a, b); if(!ff) continue; q[tot++]=(Q){a, b, ff, dep[ff], tot}; }
	sort(q, q+tot, cmp);
	for(int i=0; i<tot; ++i) {
		int x=q[i].x, y=q[i].y;
		int dec=min(g[x], g[y]);
		g[x]-=dec; g[y]-=dec; ans+=dec;
	}
	printf("%lld\n", ans<<1);
	return 0;
}

  

居然是图论题啊orzzzzzzzzzzzz

好题啊orzzzzzzzzz

首先我们每次新建一个节点表示合并的两个瓶子(而题目中的条件表明了这是一个森林!),然后发现询问的话其实就是两个瓶子的lca!

于是按lca的深度及其时间权值排序一下即可。

时间: 2024-08-11 07:42:02

【BZOJ】3712: [PA2014]Fiolki的相关文章

【BZOJ】3709: [PA2014]Bohater(贪心)

http://www.lydsy.com/JudgeOnline/problem.php?id=3709 很水的题...但是由于脑洞小..漏想了一种情况.. 首先显然能补血的先杀.. 然后杀完后从补血越多的杀..(这点我之前考虑错了QAQ) 正确性显然........ #include <cstdio> #include <cstring> #include <cmath> #include <string> #include <iostream>

【BZOJ】3319: 黑白树

http://www.lydsy.com/JudgeOnline/problem.php?id=3319 题意:给一棵n节点的树(n<=1e6),m个操作(m<=1e6),每次操作有两种:1.查询u到根的第一条黑边的编号.2.将u到v的路径全部染成黑色 #include <cstdio> #include <cstring> #include <cmath> #include <string> #include <iostream>

【bzoj】4538: [Hnoi2016]网络

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4538 维护一个数据结构支持对于一颗树的操作,需要支持: 1.对于树上的一条路径上的每个点上放一个值. 2.撤销某次操作的路劲放. 3.查询除了经过这个点的路径的最大值. 往一个路径上丢值相当于往不经过条路径的所有点上丢值. 用一个树链剖分即可维护,对于操作区间取反. 直接查询单点最大值即可. 为了维护单点最大值,线段树中的每一个点对应两个堆,用于维护插入誉删除. 防止爆空间,所以标记永久

【BZOJ】1821: [JSOI2010]Group 部落划分 Group(最小生成树+贪心)

http://www.lydsy.com:808/JudgeOnline/problem.php?id=1821 这题裸题. 本题要求最短距离最长,很明显,我们排序. 这里存在贪心,即我们把边权最小的全分给n个部落的内部,然后剩下的边最小的就是答案. 将边权较小的边分给k个部落,用并查集生成最小树,使得内部的边总是小于连到外部的边.然后分剩下k个点即可,剩下的k个点的那条边一定是部落之间最小的且最长的边. #include <cstdio> #include <cstring> #

【BZOJ】【3083】遥远的国度

树链剖分/dfs序 其实过了[BZOJ][4034][HAOI2015]T2以后就好搞了…… 链修改+子树查询+换根 其实静态树的换根直接树链剖分就可以搞了…… 因为其实只有一样变了:子树 如果root在x的子树中(以1为根dfs的时候),那么现在x的子树就变成了整个dfs序中,除去含有root的那个子树的剩下的部分,画个图大概就是这样:(红色部分为现在的子树) 我们发现,这种子树由于换根而产生变化的情况,仅当在以1为根时的树中,x是new_root的祖先时发生,那么我们判断这种情况是否发生只需

【BZOJ】2301: [HAOI2011]Problem b(莫比乌斯+分块)

http://www.lydsy.com/JudgeOnline/problem.php?id=2301 和这题不是差不多的嘛--[BZOJ]1101: [POI2007]Zap(莫比乌斯+分块) 唯一不同的地方是这题有下界.. 下界除以k的时候取上界,然后分块的时候因为有4个数,所以要分成4块来搞.. 然后就行了.. #include <cstdio> #include <cstring> #include <cmath> #include <string>

【BZOJ】1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树)

第一种做法(时间太感人): 这题我真的逗了,调了一下午,疯狂造数据,始终找不到错. 后来发现自己sb了,更新那里没有打id,直接套上u了.我.... 调了一下午啊!一下午的时光啊!本来说好中午A掉去学习第二种做法,噗 好吧,现在第一种做法是hld+seg+bst+二分,常数巨大,log^4级别,目前只会这种. 树剖后仍然用线段树维护dfs序区间,然后在每个区间建一颗平衡树,我用treap,(这题找最大啊,,,囧,并且要注意,这里的rank是比他大的数量,so,我们在二分时判断要判断一个范围,即要

最大权闭合图 &amp;&amp; 【BZOJ】1497: [NOI2006]最大获利

最大权闭合图详细请看胡伯涛论文<最小割模型在信息学竞赛中的应用>,我在这里截图它的定义以及一些东西. 假设我们有一个图,点集的出边都是连到点集的,那么称这个为闭合图.现在这些点集都有个权值,我们要选择某个闭合图使得权值最大. 回到此题: 最大获利这一题,我们可以这样看,用户群和中转站为带权的点集,用户群的权为收益,中转站的权为负的成本,即0-成本,用户群向其中两个中转站连弧,那么这个就是一个闭合图. 我们要求这个闭合图的权值和最大,即最大收益,那么就能转移到上面的求最大权闭合图的做法去了. 做

【BZOJ】1012: [JSOI2008]最大数maxnumber(树状数组+区间最值)

http://www.lydsy.com/JudgeOnline/problem.php?id=1012 树状数组原来我只懂得sum和add的操作,今天才知道可以有求区间最值的操作,我学习了一下写了个,1a了. 区间最值其实和区间求和差不多,就是将sum数组的含义转移到max,然后通过特定的区间更新max. 在区间求和中,当我们维护max[i]的时候,要找到它前面所有的max[j]来更新,在这里因为是树状数组,所以可以降成一个log级,画图可知,max[i]需要的max只有max[i-2^0],