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


    3712: [PA2014]Fiolki

    Time Limit: 30 Sec  Memory Limit: 128 MB

    Description

    化学家吉丽想要配置一种神奇的药水来拯救世界。
    吉丽有n种不同的液体物质,和n个药瓶(均从1到n编号)。初始时,第i个瓶内装着g[i]克的第i种物质。吉丽需要执行一定的步骤来配置药水,第i个步骤是将第a[i]个瓶子内的所有液体倒入第b[i]个瓶子,此后第a[i]个瓶子不会再被用到。瓶子的容量可以视作是无限的。
    吉丽知道某几对液体物质在一起时会发生反应产生沉淀,具体反应是1克c[i]物质和1克d[i]物质生成2克沉淀,一直进行直到某一反应物耗尽。生成的沉淀不会和任何物质反应。当有多于一对可以发生反应的物质在一起时,吉丽知道它们的反应顺序。每次倾倒完后,吉丽会等到反应结束后再执行下一步骤。
    吉丽想知道配置过程中总共产生多少沉淀。

    Input

    第一行三个整数n,m,k(0<=m<n<=200000,0<=k<=500000),分别表示药瓶的个数(即物质的种数),操作步数,可以发生的反应数量。
    第二行有n个整数g[1],g[2],…,g[n](1<=g[i]<=10^9),表示初始时每个瓶内物质的质量。
    接下来m行,每行两个整数a[i],b[i](1<=a[i],b[i]<=n,a[i]≠b[i]),表示第i个步骤。保证a[i]在以后的步骤中不再出现。
    接下来k行,每行是一对可以发生反应的物质c[i],d[i](1<=c[i],d[i]<=n,c[i]≠d[i]),按照反应的优先顺序给出。同一个反应不会重复出现。

    Output

    Sample Input

    3 2 1
    2 3 4
    1 2
    3 2
    2 3

    Sample Output

    6
     
     
     
    考试的时候,上来凭直觉觉得是并查集……
    此后第a[i]个瓶子不会再被用到.
    怎么看怎么是并查集嘛,然后……打了个链表的O(玄学)暴力,就开始想怎么优化查找的过程
    可是到考试结束也没想出来-_-最后只好交暴力了
    回了宿舍Troywardalao问我题面是什么(考试时候他都没看题,然而考完试他10min就淼掉了233)
    然后两个人想了10min就做出来了...(Torywar dalao为什么你想正解想得这么熟练啊)
    我们考虑这个倒药品的过程,很显然倒药品的顺序会产生影响.
    如果我们按照普通的并查集一样合并,会产生一系列问题,最大的问题就是不知道有哪些反应
    我们考虑每次合并新建节点并向他们连边(也就是重构树,参见http://www.cnblogs.com/LadyLex/p/7275821.html)
    这样,我们就把每一次合并拆开,并且独立考虑每次合并的过程
    接下来使用了类似离线的思想,我们首先处理一个计算lca的方式(tarjan,倍增随意了),然后考虑:
    对于每一对可以反应的物质,他们可能,也只可能在他们重构树上lca处反应
    既然这样,我们就可以把每个反应添加到他们的lca上
    随后,在扫一遍重构时新添加到点,也就是执行一遍倒药品的过程,并且处理可能发生的反应
    总的复杂度是O(m+nlogn+klogn+k),分别对应重构,ST表预处理,向lca添加反应,处理合并过程
    (ps:其实还是有一点遗憾,明明自己已经打过重构树的题了,考试时候却没想到.看来我对知识的掌握程度还没有到那么熟练的程度....联赛之前一定要把已经学的知识掌握扎实啊...)
    代码见下:
     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #include <vector>
     5 using namespace std;
     6 const int N=200010,K=500010;
     7 typedef long long LL;
     8 LL sum;
     9 int n,m,k,w[N],fa[N<<1],bin[25];
    10 int e,adj[N<<1],cnt,f[N<<1][19],deep[N<<1];
    11 int find(int a){return fa[a]==a?a:fa[a]=find(fa[a]);}
    12 inline int min(int a,int b){return a<b?a:b;}
    13 struct data{int a,b;data(int x=0,int y=0){a=x,b=y;}}step[N];
    14 struct edge{int zhong,next;}s[N<<1];
    15 vector<data>re[N<<1];
    16 inline void add(int qi,int zhong)
    17     {s[++e].zhong=zhong;s[e].next=adj[qi];adj[qi]=e;}
    18 void dfs(int rt)
    19 {
    20     deep[rt]=deep[f[rt][0]]+1;
    21     for(int i=adj[rt];i;i=s[i].next)
    22         dfs(s[i].zhong);
    23 }
    24 inline void ST()
    25 {
    26     for(int i=1;i<=18;i++)
    27         for(int j=1;j<=cnt;j++)
    28             f[j][i]=f[f[j][i-1]][i-1];
    29 }
    30 inline int LCA(int a,int b)
    31 {
    32     if(deep[a]<deep[b])swap(a,b);
    33     int cha=deep[a]-deep[b];
    34     for(int j=18;~j;j--)
    35         if(cha&bin[j])a=f[a][j];
    36     if(a==b)return a;
    37     for(int j=18;~j;j--)
    38         if(f[a][j]!=f[b][j])a=f[a][j],b=f[b][j];
    39     return f[a][0];
    40 }
    41 int main()
    42 {
    43     bin[0]=1;for(int i=1;i<=20;i++)bin[i]=bin[i-1]<<1;
    44     int a,b,lca;scanf("%d%d%d",&n,&m,&k);cnt=n;
    45     for(int i=1;i<=n+m;i++)fa[i]=i;
    46     for(int i=1;i<=n;i++)scanf("%d",&w[i]);
    47     for(int i=1;i<=m;i++)
    48         scanf("%d%d",&step[i].a,&step[i].b),
    49         a=find(step[i].a),b=find(step[i].b),
    50         fa[a]=fa[b]=f[a][0]=f[b][0]=++cnt,
    51         add(cnt,a),add(cnt,b);
    52     ST();
    53     for(int i=1;i<=cnt;i++)
    54         if(!deep[i])dfs(find(i));
    55     for(int i=1;i<=k;i++)
    56     {
    57         scanf("%d%d",&a,&b);
    58         if(find(a)==find(b))
    59             lca=LCA(a,b),re[lca].push_back(data(a,b));
    60     }
    61     for(int i=n+1;i<=cnt;i++)
    62         for(int j=0,len=re[i].size();j<len;j++)
    63             a=min(w[re[i][j].a],w[re[i][j].b]),
    64             w[re[i][j].a]-=a,w[re[i][j].b]-=a,sum+=a;
    65     printf("%lld
    ",sum<<1);
    66 }
  • 相关阅读:
    ES6中的class的详解
    JavaSrcipt中字符串和数组容易搞混的操作
    ES6中的数据结构Map的理解和描述
    ES6中新增数据结构Set的理解和用法详情描述
    ES6中的Promise的用法总结
    JS中的async/await的用法和理解
    字节跳动、拼多多前端面经
    前端项目优化 -Web 开发常用优化方案、Vue & React 项目优化
    记几个 DOM 操作技巧
    JavaScript 面试题
  • 原文地址:https://www.cnblogs.com/LadyLex/p/7470305.html
Copyright © 2020-2023  润新知