[关闭]
@ysner 2018-07-27T00:08:22.000000Z 字数 2106 阅读 2002

[PA2014]Fiolki

LCA 图论


题面

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

解析

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

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

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<algorithm>
  7. #define re register
  8. #define il inline
  9. #define ll long long
  10. #define max(a,b) ((a)>(b)?(a):(b))
  11. #define min(a,b) ((a)<(b)?(a):(b))
  12. #define fp(i,a,b) for(re int i=a;i<=b;i++)
  13. #define fq(i,a,b) for(re int i=a;i>=b;i--)
  14. using namespace std;
  15. const int N=5e5+100;
  16. struct Edge{int to,nxt;}e[N<<1];
  17. 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];
  18. int n,g[N],tot,m,k,cnt,h[N],ff,d[N],sz[N],son[N],f[N],top[N],pos[N];
  19. ll ans;
  20. 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;}
  21. il ll gi()
  22. {
  23. re ll x=0,t=1;
  24. re char ch=getchar();
  25. while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
  26. if(ch=='-') t=-1,ch=getchar();
  27. while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  28. return x*t;
  29. }
  30. il void dfs1(re int u,re int fa)
  31. {
  32. d[u]=d[fa]+1;f[u]=fa;sz[u]=1;
  33. for(re int i=h[u];i+1;i=e[i].nxt)
  34. {
  35. re int v=e[i].to;
  36. if(v==fa) continue;
  37. dfs1(v,u);
  38. sz[u]+=sz[v];
  39. if(sz[son[u]]<sz[v]) son[u]=v;
  40. }
  41. }
  42. il void dfs2(re int u,re int up)
  43. {
  44. top[u]=up;
  45. if(son[u]) dfs2(son[u],up);
  46. for(re int i=h[u];i+1;i=e[i].nxt)
  47. {
  48. re int v=e[i].to;
  49. if(v==f[u]||v==son[u]) continue;
  50. dfs2(v,v);
  51. }
  52. }
  53. il int getlca(re int u,re int v)
  54. {
  55. while(top[u]^top[v])
  56. {
  57. if(d[top[u]]<d[top[v]]) swap(u,v);
  58. u=f[top[u]];
  59. }
  60. return d[u]<d[v]?u:v;
  61. }
  62. int main()
  63. {
  64. memset(h,-1,sizeof(h));
  65. n=gi();m=gi();k=gi();
  66. fp(i,1,n) pos[i]=i,g[i]=gi();
  67. fp(i,1,m)
  68. {
  69. re int u=gi(),v=gi(),ff=n+i;
  70. add(pos[u],ff);add(pos[v],ff);pos[v]=ff;
  71. }
  72. fq(i,n+m,1) if(!f[i]) dfs1(i,0),dfs2(i,i);
  73. fp(i,1,k)
  74. {
  75. re int u=gi(),v=gi(),lca=getlca(u,v);
  76. if(!lca) continue;//不反应
  77. a[++tot]=(dat){u,v,lca,d[lca],i};
  78. }
  79. sort(a+1,a+1+tot);
  80. fp(i,1,tot)
  81. {
  82. re int u=a[i].u,v=a[i].v,gg=min(g[u],g[v]);
  83. g[u]-=gg;g[v]-=gg;ans+=gg*2;
  84. }
  85. printf("%lld\n",ans);
  86. return 0;
  87. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注