[PA2014]Fiolki

https://zybuluo.com/ysner/note/1228184

题面

吉丽有\(n\)种不同的液体物质,和\(n\)个药瓶(均从1到n编号)。吉丽需要执行一定的\(k\)步骤来配置药水,步骤是将某个瓶子内的所有液体倒入另一个瓶子。
吉丽知道某\(m\)对液体物质在一起时会发生反应产生沉淀。生成的沉淀不会和任何物质反应。当有多于一对可以发生反应的物质在一起时,吉丽知道它们的反应顺序。每次倾倒完后,吉丽会等到反应结束后再执行下一步骤。吉丽想知道配置过程中总共产生多少沉淀。

  • \(m,n\leq2*10^5,k\leq5*10^5\)

    解析

    这题真是脑洞神题
    发现模拟妥妥的\(O(mk)\)
    记得约束关系一般都能牵扯到图论。(然后我就懵了
    实际上,这种化学反应(化合反应)很容易让我们想起树形结构

于是一切都自然了。
我们把生成物作为一对反应物的父亲,反应完就把反应物的位置改到生成物那儿。
这样能构成森林。(图不一定联通
显然深度越大,反应顺序越靠前的越先反应。
按此顺序,通过找\(lca\)得到生成物,一一模拟即可。
复杂度\(O(klogn)\)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define re register
#define il inline
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
const int N=5e5+100;
struct Edge{int to,nxt;}e[N<<1];
struct dat{int u,v,lca,deep,id;bool operator < (const dat &o) const{return (deep>o.deep)||(deep==o.deep&&id<o.id);}}a[N<<1];
int n,g[N],tot,m,k,cnt,h[N],ff,d[N],sz[N],son[N],f[N],top[N],pos[N];
ll ans;
il void add(re int u,re int v){e[++cnt]=(Edge){v,h[u]};h[u]=cnt;e[++cnt]=(Edge){u,h[v]};h[v]=cnt;}
il ll gi()
{
  re ll x=0,t=1;
  re char ch=getchar();
  while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
  if(ch=='-') t=-1,ch=getchar();
  while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  return x*t;
}
il void dfs1(re int u,re int fa)
{
  d[u]=d[fa]+1;f[u]=fa;sz[u]=1;
  for(re int i=h[u];i+1;i=e[i].nxt)
    {
      re int v=e[i].to;
      if(v==fa) continue;
      dfs1(v,u);
      sz[u]+=sz[v];
      if(sz[son[u]]<sz[v]) son[u]=v;
    }
}
il void dfs2(re int u,re int up)
{
  top[u]=up;
  if(son[u]) dfs2(son[u],up);
  for(re int i=h[u];i+1;i=e[i].nxt)
    {
      re int v=e[i].to;
      if(v==f[u]||v==son[u]) continue;
      dfs2(v,v);
    }
}
il int getlca(re int u,re int v)
{
  while(top[u]^top[v])
    {
      if(d[top[u]]<d[top[v]]) swap(u,v);
      u=f[top[u]];
    }
  return d[u]<d[v]?u:v;
}
int main()
{
  memset(h,-1,sizeof(h));
  n=gi();m=gi();k=gi();
  fp(i,1,n) pos[i]=i,g[i]=gi();
  fp(i,1,m)
    {
      re int u=gi(),v=gi(),ff=n+i;
      add(pos[u],ff);add(pos[v],ff);pos[v]=ff;
    }
  fq(i,n+m,1) if(!f[i]) dfs1(i,0),dfs2(i,i);
  fp(i,1,k)
  {
    re int u=gi(),v=gi(),lca=getlca(u,v);
    if(!lca) continue;//不反应
    a[++tot]=(dat){u,v,lca,d[lca],i};
  }
  sort(a+1,a+1+tot);
  fp(i,1,tot)
    {
      re int u=a[i].u,v=a[i].v,gg=min(g[u],g[v]);
      g[u]-=gg;g[v]-=gg;ans+=gg*2;
    }
    printf("%lld\n",ans);
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/yanshannan/p/9375209.html
今日推荐