• [bzoj3712][PA2014]Fiolki_倍增LCA


    Fiolki bzoj-3712 PA-2014

    题目大意题目链接

    注释:略。


    想法

    神题!

    我们建树:对于一次倾倒操作,我们弄一个新的大瓶子作为两个合并瓶子的父亲节点,与两个瓶子相连。

    对于一个给定的化学反应,显然他们在这棵又操作构成的森林中他们的LCA处实现。

    所以我们对于所有的操作直接建树。

    我们枚举所有的反应,每个反应对应两个物质的LCA。我们将反应按照对应LCA的深度为第一关键字,反应的优先级为第二关键字排序。

    紧接着我们顺次枚举所有的反应,统计答案并将相应物质剩余量相减即可。

    最后,附上丑陋的代码... ...

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 200010 
    #define K 500010 
    using namespace std;
    int to[N<<2],nxt[N<<2],head[N<<1],tot;
    int F[N<<1],f[21][N<<1],dep[N<<1];
    int a[N],cnt;
    inline char nc() {static char *p1,*p2,buf[100000]; return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;}
    int rd() {int x=0; char c=nc(); while(!isdigit(c)) c=nc(); while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=nc(); return x;}
    inline void add(int x,int y) {to[++tot]=y; nxt[tot]=head[x]; head[x]=tot;}
    int find(int x) {return F[x]==x?x:F[x]=find(F[x]);}
    struct Node {int x,y,fr,dp;}opr[K];
    inline bool cmp(const Node &a,const Node &b) {return a.dp==b.dp?a.fr<b.fr:a.dp>b.dp;}
    void dfs(int pos,int fa)
    {
    	dep[pos]=dep[fa]+1;
    	f[0][pos]=fa; for(int i=1;i<=20;i++) f[i][pos]=f[i-1][f[i-1][pos]];
    	for(int i=head[pos];i;i=nxt[i]) if(to[i]!=fa) dfs(to[i],pos);
    }
    int lca(int x,int y)
    {
    	if(dep[x]<dep[y]) swap(x,y);
    	for(int i=20;~i;i--) if(dep[f[i][x]]>=dep[y]) x=f[i][x];
    	if(x==y) return x;
    	for(int i=20;~i;i--) if(f[i][x]!=f[i][y]) x=f[i][x],y=f[i][y];
    	return f[0][x];
    }
    int main()
    {
        // freopen("3712.in","r",stdin);
        // freopen("3712.out","w",stdout);
    	int n=rd(),m=rd(),k=rd(); for(int i=1;i<=n;i++) a[i]=rd(),F[i]=i;
        for(int i=1;i<=n*2;i++) F[i]=i;
    	cnt=n;
    	for(int i=1;i<=m;i++)
    	{
    		int x=find(rd()),y=find(rd());
    		cnt++;
    		add(cnt,x);
    		add(cnt,y);
    		F[x]=F[y]=cnt;
    	}
    	dfs(cnt,cnt);
    	for(int i=1;i<=k;i++) opr[i].x=rd(),opr[i].y=rd(),opr[i].fr=i,opr[i].dp=dep[lca(opr[i].x,opr[i].y)];
    	sort(opr+1,opr+k+1,cmp);
    	int ans=0;
    	for(int i=1;i<=k;i++)
    	{
    		int now=min(a[opr[i].x],a[opr[i].y]);
    		ans+=now;
    		a[opr[i].x]-=now; a[opr[i].y]-=now;
    	}
    	printf("%lld
    ",(long long)ans*2);
        // fclose(stdin); fclose(stdout);
    	return 0;
    }
    

    小结:好题啊,关键是发现其中树形结构并想到LCA处发生反应。

  • 相关阅读:
    .net中的委托
    GridView, DataList and ListBox 行 单击与双击事件处理
    ChineseCalendar类[转]
    数据契约(DataContract)
    XPath 语法(复习)
    正则表达式学习笔记
    瑞星笔试:现场上机做题[转]
    发送带有附件的电子邮件使用 Cdosys.dll 库
    DataContractJsonSerializer 类 操作json类型数据
    i guess a bug on Castle
  • 原文地址:https://www.cnblogs.com/ShuraK/p/9891301.html
Copyright © 2020-2023  润新知