【BZOJ】3712: [PA2014]Fiolki
http://www.lydsy.com/JudgeOnline/problem.php?id=3712
题意:n个瓶子,第i个瓶子里又g[i]克物质。m次操作,第i次操作把第a[i]个瓶子的东西全部倒到第b[i]个瓶子里(保证之后不出现a[i])。k种反应,其中c[i]和d[i]反应,而且如果一个瓶子里有多种反应则优先反应靠前的。每次反应对答案贡献为min(g[i], g[i])*2(m<n<=200000, k<=500000)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=200005, M=200005, nQ=500005; ll ans; int n, m, K, ihead[N+M], cnt, pos[N], g[N], dep[N+M], f[N+M][20], tot; struct E { int next, to; } e[(N+M)<<1]; struct Q { int x, y, ff, dep, id; } q[nQ]; bool cmp(const Q &a, const Q &b) { return a.dep==b.dep?a.id<b.id:a.dep>b.dep; } void add(int x, int y) { e[++cnt]=(E){ihead[x], y}; ihead[x]=cnt; e[++cnt]=(E){ihead[y], x}; ihead[y]=cnt; } void dfs(int x) { for(int i=1; i<=19; ++i) f[x][i]=f[f[x][i-1]][i-1]; for(int i=ihead[x]; i; i=e[i].next) if(e[i].to!=f[x][0]) { f[e[i].to][0]=x; dep[e[i].to]=dep[x]+1; dfs(e[i].to); } } int lca(int x, int y) { if(dep[x]<dep[y]) swap(x, y); int d=dep[x]-dep[y]; for(int i=19; i>=0; --i) if((d>>i)&1) x=f[x][i]; if(x==y) return x; for(int i=19; i>=0; --i) if(f[x][i]!=f[y][i]) x=f[x][i], y=f[y][i]; return f[x][0]; } int main() { scanf("%d%d%d", &n, &m, &K); for(int i=1; i<=n; ++i) pos[i]=i; for(int i=1; i<=n; ++i) scanf("%d", &g[i]); for(int i=1; i<=m; ++i) { int a, b; scanf("%d%d", &a, &b); int ff=n+i; add(pos[a], ff); add(pos[b], ff); pos[b]=ff; } for(int i=n+m; i>=1; --i) if(!f[i][0]) dfs(i); for(int i=1; i<=K; ++i) { int a, b, ff; scanf("%d%d", &a, &b); ff=lca(a, b); if(!ff) continue; q[tot++]=(Q){a, b, ff, dep[ff], tot}; } sort(q, q+tot, cmp); for(int i=0; i<tot; ++i) { int x=q[i].x, y=q[i].y; int dec=min(g[x], g[y]); g[x]-=dec; g[y]-=dec; ans+=dec; } printf("%lld\n", ans<<1); return 0; }
居然是图论题啊orzzzzzzzzzzzz
好题啊orzzzzzzzzz
首先我们每次新建一个节点表示合并的两个瓶子(而题目中的条件表明了这是一个森林!),然后发现询问的话其实就是两个瓶子的lca!
于是按lca的深度及其时间权值排序一下即可。
博客地址:www.cnblogs.com/iwtwiioi 本文为博主原创文章,未经博主允许不得转载。一经发现,必将追究法律责任。