【BZOJ3712】Fiolki(并查集重构树)

题面

BZOJ

题解

很神仙的题目。

我们发现所有的合并关系构成了一棵树。

那么两种不同的东西如果产生反应,一定在两个联通块恰好联通的时候反应。

那么,我们按照并查集的合并顺序,类似于克鲁斯卡尔重构树的方法构建一个并查集重构树,

发现所有的反应恰好在两者的\(LCA\)处发生,

所以把所有可以发生的翻译拿出来,

按照\(LCA\)的深度为第一关键字,反应的优先级为第二关键字排序。

然后按顺序依次计算答案就好了。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define ll long long
#define RG register
#define MAX 500500
inline int read()
{
RG int x=0,t=1;RG char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
ll ans;
int n,m,g[MAX],k;
struct Line{int v,next;}e[MAX];
int h[MAX],cnt=1;
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
int size[MAX],hson[MAX],top[MAX],fa[MAX],dep[MAX];
void dfs1(int u,int ff)
{
dep[u]=dep[ff]+1;fa[u]=ff;size[u]=1;
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;if(v==ff)continue;
dfs1(v,u);size[u]+=size[v];
if(size[v]>size[hson[u]])hson[u]=v;
}
}
void dfs2(int u,int tp)
{
top[u]=tp;
if(hson[u])dfs2(hson[u],tp);
for(int i=h[u];i;i=e[i].next)
if(e[i].v!=hson[u]&&e[i].v!=fa[u])
dfs2(e[i].v,e[i].v);
}
int LCA(int u,int v)
{
while(top[u]^top[v])dep[top[u]]<dep[top[v]]?v=fa[top[v]]:u=fa[top[u]];
return dep[u]<dep[v]?u:v;
}
int f[MAX],tot;
struct Event{int dep,id,u,v;}p[MAX];
bool operator<(Event a,Event b)
{
if(a.dep!=b.dep)return a.dep>b.dep;
return a.id<b.id;
}
int getf(int x){return x==f[x]?x:f[x]=getf(f[x]);}
int main()
{
n=read();m=read();k=read();
for(int i=1;i<=n;++i)g[i]=read(),f[i]=i;
for(int i=1;i<=m;++i)
{
int a=read(),b=read();
Add(n+i,f[getf(a)]);Add(n+i,f[getf(b)]);
f[getf(a)]=f[getf(b)]=n+i;f[n+i]=n+i;
}
for(int i=n+m;i;--i)if(!dep[i])dfs1(i,0),dfs2(i,i);
for(int i=1;i<=k;++i)
{
int u=read(),v=read();
if(getf(u)!=getf(v))continue;
int s=LCA(u,v);
p[++tot]=(Event){dep[s],i,u,v};
}
sort(&p[1],&p[tot+1]);
for(int i=1;i<=tot;++i)
{
int u=p[i].u,v=p[i].v;
int s=min(g[u],g[v]);
ans+=s;g[u]-=s;g[v]-=s;
}
printf("%lld\n",ans+ans);
}

【BZOJ3712】Fiolki(并查集重构树)的更多相关文章

  1. BZOJ3712[PA2014]Fiolki——并查集重构树

    题目描述 化学家吉丽想要配置一种神奇的药水来拯救世界.吉丽有n种不同的液体物质,和n个药瓶(均从1到n编号).初始时,第i个瓶内装着g[i]克的第i种物质.吉丽需要执行一定的步骤来配置药水,第i个步骤 ...

  2. [学习笔记]kruskal重构树 && 并查集重构树

    Kruskal 重构树 [您有新的未分配科技点][BZOJ3545&BZOJ3551]克鲁斯卡尔重构树 kruskal是一个性质优秀的算法 加入的边是越来越劣的 科学家们借这个特点尝试搞一点事 ...

  3. [note]克鲁斯卡尔重构树

    克鲁斯卡尔重构树 又叫并查集重构树 大概在NOI2018之前还是黑科技 现在?烂大街了 主要是针对图上的对边有限制的一类问题 比如每次询问一个点u不能经过边权大于w的边能走到的第k大点权是多少 也就是 ...

  4. [BZOJ3712]Fiolki 重构树(并查集)

    3712: [PA2014]Fiolki Time Limit: 30 Sec  Memory Limit: 128 MB Description 化学家吉丽想要配置一种神奇的药水来拯救世界.吉丽有n ...

  5. NOI2018Day1T1 归程 并查集 kruskal kruskal重构树 倍增表 Dijkstra

    原文链接https://www.cnblogs.com/zhouzhendong/p/NOI2018Day1T1.html 题目传送门 - 洛谷P4768 题意 给定一个无向连通图,有 $n$ 个点 ...

  6. [NOI2018]归程(可持久化并查集,Kruskal重构树)

    解法一: 1.首先想到离线做法:将边和询问从大到小排序,并查集维护连通块以及每个连通块中所有点到1号点的最短距离.$O(n\log n)$ 配合暴力等可以拿到75分. 2.很容易想到在线做法,使用可持 ...

  7. CF1253F Cheap Robot(神奇思路,图论,最短路,最小生成树/Kruskal 重构树/并查集)

    神仙题. 先考虑平方级别的暴力怎么做. 明显答案有单调性,先二分 \(c\). 先最短路预处理 \(dis_u\) 表示 \(u\) 到离它最近的充电站的距离(一开始把 \(1\) 到 \(k\) 全 ...

  8. [HDU 3712] Fiolki (带边权并查集+启发式合并)

    [HDU 3712] Fiolki (带边权并查集+启发式合并) 题面 化学家吉丽想要配置一种神奇的药水来拯救世界. 吉丽有n种不同的液体物质,和n个药瓶(均从1到n编号).初始时,第i个瓶内装着g[ ...

  9. [bzoj3123][sdoi2013森林] (树上主席树+lca+并查集启发式合并+暴力重构森林)

    Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数 ...

随机推荐

  1. runtime如何实现weak属性

    首先了解weak是一种非拥有关系,属性所值对象销毁时,属性值会清空(nil). Runtime对注册的类会进行布局,对于weak对象会放入hash表中,用weak指向的内存地址作为key,当对象引用计 ...

  2. [css 实践篇]CSS中的尺寸单位

    绝对单位 px: Pixel 像素 pt: Points 磅 pc: Picas 派卡 in: Inches 英寸 mm: Millimeter 毫米 cm: Centimeter 厘米 q: Qua ...

  3. python全栈开发-面向对象-初识

    python_16_day 函数总结: https://www.processon.com/view/link/5b718274e4b0555b39e1055f 面向过程的程序设计的核心是过程(流水线 ...

  4. JUC——TimeUnit工具类(二)

    TimeUnit工具类 在java.util.concurrent开发包里面提供有一个TimeUnit类,这个类单独看它的描述是一个时间单元类.该类是一个枚举类,这也是juc开包里面唯一的一个枚举类. ...

  5. Codeforces Round #502 (in memory of Leopoldo Taravilse, Div. 1 + Div. 2) E. The Supersonic Rocket

    这道题比赛之后被重新加了几个case,很多人现在都过不了了 算法就是先求凸包,然后判断两个凸包相等 我们可以吧凸包序列化为两点距离和角度 角度如果直接拿向量的叉积是不对的,,因为钝角和锐角的叉积有可能 ...

  6. POJ-3273(二分)

    //题意:给出农夫在n天中每天的花费,要求把这n天分作m组, //每组的天数必然是连续的,要求分得各组的花费之和应该尽可能地小,最后输出各组花费之和中的最大值. //思路:看到各组最小和最大的,果断上 ...

  7. MySQL事务、并发问题、锁机制

    MySQL事务,并发问题,锁机制 1.什么是事务 事务是一条或多条数据库操作语句的组合,具备ACID,4个特点. 原子性:要不全部成功,要不全部撤销 隔离性:事务之间相互独立,互不干扰 一致性:数据库 ...

  8. 译 - 高可用的mesos计算框架设计

    原文地址 http://mesos.apache.org/documentation/latest/high-availability-framework-guide/ 阅读建议:有写过或者看过Mes ...

  9. 在PHP中,是以分好结束一条语句的吗

    在PHP中,是以分号结束一条语句的,这个和C语言类似. 但是,有一条例外,对于PHP结束tag之前的语句,是可以不写分号的: <?php if ($a == $b) { echo "R ...

  10. .net组件和com组件&托管代码和非托管代码

    com组件和.net组件: COM组件是非托管对象,可以不需要.NET框架而直接运行,.NET框架组件是托管对象,必须有.NET框架的支撑才能运行. COM组件有独立的类型库文件,而.NET组件是通过 ...