【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);
}

最新文章

  1. webSocket详解
  2. TortoiseSVN使用教程
  3. coroSync packmarker
  4. VirtualBox 虚拟 Ubuntu 的一些感想
  5. 【转】HTTP-only Cookie 脚本获取JSESSIONID的方法
  6. BZOJ 3203 sdoi 2013 保护出题人
  7. ASP.NET MVC 学习5、登陆页面改为SSO验证
  8. left join 、right join 、inner join和 full join的区别
  9. Java I/O流-ObjectInputStream、ObjectOutputStream
  10. ThreadLocal 与 static 变量
  11. windows下vue+webpack前端开发环境搭建及nginx部署
  12. Javascript之pixi框架学习
  13. 【javaFX学习】(一) 建一个简单的界面
  14. 使用/dev/poll的str_cli函数
  15. instanceof简单用法
  16. [Tensorflow] **Android Meets TensorFlow
  17. (转)C#.NET WINFORM应用程序中控制应用程序只启动一次
  18. 利用Python实现FGO自动战斗脚本,再也不用爆肝啦~
  19. Android将Log写入文件
  20. AWS CSAA -- 04 AWS Object Storage and CDN - S3 Glacier and CloudFront(二)

热门文章

  1. 【转】ERROR 2003 (HY000): Can&#39;t connect to MySQL server on &#39;192.168.1.165&#39; (113)
  2. C++自学第一课:函数
  3. eclipse集成testng插件(离线安装方式)
  4. idea compare功能 之一次bug修复
  5. 【python 3.6】python读取json数据存入MySQL(一)
  6. [T-ARA][HUE]
  7. apply新用法,最大值查找
  8. 多源最短路——Floyd算法
  9. 贪吃蛇GUI Prototype
  10. Java接口interface,匿名内部类