BZOJ3712: [PA2014]Fiolki
LCA·乱搞
题解:
哇塞好棒棒的题啊!
显然的做法是
O(mk)
的,嗯,换种思路。
如果我们能快速知道反应的发生顺序呢?
可惜没有如果……
是有的!
按照操作的顺序,为每个操作新建一个节点,当然每个原始的瓶子也是节点,两个儿子分别是反应的两个瓶子。
这样就长成一片森林啦~
然后两种物质的LCA的深度不就是它们反应的顺序吗?
排一下序模拟一下就行了。
注意处理好森林。
可怜的我还把LCA写错了QwQ
Code:
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#define D(x) cout<<#x<<" = "<<x<<" "
#define E cout<<endl
using namespace std;
const int N = 500005;
int n,m,k,g[N],dep[N],ptr[N],pa[N][20],sz;
long long ans;
struct FanYing{
int a,b,id,lca;
} f[N];
bool cmp(const FanYing &x, const FanYing &y){
return dep[x.lca]>dep[y.lca] || (dep[x.lca]==dep[y.lca] && x.id<y.id);
}
struct Node{
int lch,rch,pa;
} t[N];
void work(int a,int b){
++sz; //D(a); D(b); D(sz); E;
t[sz].lch=ptr[a]; t[ptr[a]].pa=sz;
t[sz].rch=ptr[b]; t[ptr[b]].pa=sz;
ptr[b]=sz;
}
void dfs(int u){
if(!t[u].lch) return;
dep[t[u].lch]=dep[t[u].rch]=dep[u]+1;
pa[t[u].lch][0]=pa[t[u].rch][0]=u;
dfs(t[u].lch);
dfs(t[u].rch);
}
void init(){
for(int j=1;j<20;j++)
for(int i=1;i<=sz;i++)
pa[i][j]=pa[pa[i][j-1]][j-1];
}
int LCA(int a,int b){
if(dep[a]<dep[b]) swap(a,b);
int cha=dep[a]-dep[b];
for(int i=0;(1<<i)<=cha;i++){
if(cha&(1<<i)) a=pa[a][i];
}
if(a!=b){
for(int i=19;i>=0;i--){
if(pa[a][i]!=pa[b][i]){
a=pa[a][i]; b=pa[b][i];
}
}
a=pa[a][0];
}
return a;
}
int main(){
freopen("a.in","r",stdin);
scanf("%d%d%d",&n,&m,&k);
sz=n; for(int i=1;i<=n;i++) ptr[i]=i;
for(int i=1;i<=n;i++) scanf("%d",&g[i]);
int a,b;
for(int i=1;i<=m;i++){
scanf("%d%d",&a,&b);
work(a,b);
}
for(int i=1;i<=sz;i++) if(!t[i].pa) dfs(i);
init();
// for(int i=1;i<=sz;i++) D(pa[i][0]), D(pa[i][1]), D(dep[i]), E;
for(int i=1;i<=k;i++){
scanf("%d%d",&f[i].a,&f[i].b);
f[i].id=i; f[i].lca=LCA(f[i].a,f[i].b);
// D(f[i].lca); E;
}
sort(f+1,f+1+k,cmp);
for(int i=1;i<=k;i++){
if(f[i].lca==0) continue;
int tp=min(g[f[i].a],g[f[i].b]);
ans+=tp*2; g[f[i].a]-=tp; g[f[i].b]-=tp;
}
printf("%lld\n",ans);
}