题解
网络流模板题。
考虑如何将一合法方案用流量图表示:
对于一个商人,从起点
s
s
s 连一条流量为
c
i
c_i
ci,的边到
i
i
i,然后因为其商品可以在
a
i
→
b
i
a_i \to b_i
ai→bi 上分布,所以把
i
i
i 向
a
i
→
b
i
a_i \to b_i
ai→bi 上每个点连一条流量无限的边。
最后对于树上的点,向汇点
t
t
t 连一条流量为
w
i
w_i
wi 的边即可。
最后由于边数过大,用树剖+线段树优化建图即可。
代码
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N=3e5+10;
const LL INF=1e11;
int n,m,w[N];
int tot=1,ver[N<<5],fst[N<<5],nxt[N<<5],now[N<<5];
LL edge[N<<5];
inline void add(int x,int y,LL z){ver[++tot]=y;nxt[tot]=fst[x];fst[x]=tot;edge[tot]=z;}
vector<int> e[N];
int lt[N],d[N],rt[N],dfn,sz[N],son[N],ft[N],dep[N],maxn,top[N],idfn[N];
int s,t;
LL maxflow,ans;
void dfs_pre(int x,int fa){
int mx=0;sz[x]=1;d[x]=d[fa]+1;ft[x]=fa;
for(int i=0;i<(int)e[x].size();++i){
int y=e[x][i];if(y==fa)continue;
dfs_pre(y,x);sz[x]+=sz[y];
if(sz[y]>sz[mx])mx=y;
}
son[x]=mx;
}
void dfs_get(int x,int fa){
lt[x]=++dfn;idfn[dfn]=x;
if(son[x])top[son[x]]=top[x],dfs_get(son[x],x);
for(int i=0;i<(int)e[x].size();++i){
int y=e[x][i];if(y==fa||y==son[x])continue;
top[y]=y;dfs_get(y,x);
}
rt[x]=dfn;
}
inline int LCA(int x,int y){
while(top[x]!=top[y]){
if(d[top[x]]>=d[top[y]])x=ft[top[x]];
else y=ft[top[y]];
}
return (d[x]>=d[y])?y:x;
}
void build(int p,int l,int r){
maxn=max(maxn,p+m);
if(l==r){
add(p+m,t,w[idfn[l]]);
add(t,p+m,0);
return;
}
int mid=(l+r)>>1;
build(p<<1,l,mid);build((p<<1)|1,mid+1,r);
add(p+m,(p<<1)+m,INF);add((p<<1)+m,p+m,0);
add(p+m,(p<<1)+m+1,INF);add((p<<1)+m+1,p+m,0);
}
void jia(int i,int p,int l,int r,int L,int R){
if(l>=L&&r<=R){
add(i,p+m,INF);
add(p+m,i,0);
return;
}
int mid=(l+r)>>1;
if(L<=mid)jia(i,p<<1,l,mid,L,R);
if(R>mid)jia(i,(p<<1)|1,mid+1,r,L,R);
}
inline void cale(int i,int x,int y){
while(top[x]!=top[y]){
int F=top[x];
jia(i,1,1,n,lt[F],lt[x]);
// cout<<"FAQ "<<lt[F]<<" "<<lt[x]<<" "<<x<<" "<<F<<endl;
x=ft[F];
}
if(x!=y)jia(i,1,1,n,lt[y]+1,lt[x]);
}
queue<int> q;
inline bool bfs(){
while(q.size())q.pop();
for(int i=1;i<=maxn;++i)dep[i]=0;
dep[t]=0;
q.push(s);now[s]=fst[s];dep[s]=1;
while(q.size()){
int x=q.front();q.pop();
// cout<<"FAQ "<<x<<endl;
for(int i=fst[x];i;i=nxt[i]){
int y=ver[i];if(!edge[i]||dep[y])continue;
dep[y]=dep[x]+1;
q.push(y);now[y]=fst[y];
if(y==t)return true;
}
}
return false;
}
inline LL dinic(int x,LL flow){
LL res=flow;
if(x==t)return flow;
for(int i=now[x];i;i=nxt[i]){
now[x]=i;int y=ver[i];
if(!edge[i]||dep[y]!=dep[x]+1)continue;
LL k=dinic(y,min(edge[i],res));
if(!k)dep[y]=0;
res-=k;
edge[i]-=k;
edge[i^1]+=k;
if(!res)break;
}
return flow-res;
}
int main(){
// freopen("013.in","r",stdin);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)scanf("%d",&w[i]);
for(int i=1;i<n;++i){
int x,y;scanf("%d%d",&x,&y);
e[x].push_back(y);e[y].push_back(x);
}
s=0;t=5*n+m+1;
dfs_pre(1,0);top[1]=1;dfs_get(1,0);
build(1,1,n);
// cout<<"FAq "<<maxn<<" "<<tot<<endl;
for(int i=1;i<=m;++i){
int a,b,c;scanf("%d%d%d",&a,&b,&c);
int k=LCA(a,b);
// cout<<"LCA "<<k<<endl;
cale(i,a,k);cale(i,b,k);
add(s,i,c);add(i,s,0);jia(i,1,1,n,lt[k],lt[k]);
}
// cout<<"FAQ "<<tot<<" "<<t<<endl;
while(bfs()){
// cout<<"Dinic "<<" "<<ans<<endl;
ans+=dinic(s,INF);
}
printf("%lld\n",ans);
return 0;
}