BZOJ3322 : [Scoi2013]摩托车交易

时间:2021-05-24 18:01:23

求出最大生成树,则两点间的最大容量为树上两点间的边权的最小值。

设$lim[i]$表示第$i$个订单的城市允许携带的黄金上限,则

$lim[i]=\min(lim[i+1],a[i]和a[i+1]点间最大容量)+\max(0,-b[a[i]])$

然后依次模拟即可,时间复杂度$O(m\log n)$。

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=100010,K=16;
const ll inf=1LL<<60;
int n,m,q,i,j,a[N],b[N],c[N],fa[N],g[N],v[N<<1],nxt[N<<1],ed;
int d[N],f[K+1][N];
ll w[N<<1],fm[K+1][N],now,tmp,lim[N];
struct E{int x,y;ll z;}e[300010];
inline bool cmp(const E&a,const E&b){return a.z>b.z;}
int F(int x){return fa[x]==x?x:fa[x]=F(fa[x]);}
inline void add(int x,int y,ll z){
v[++ed]=y;w[ed]=z;nxt[ed]=g[x];g[x]=ed;
v[++ed]=x;w[ed]=z;nxt[ed]=g[y];g[y]=ed;
}
void dfs(int x,int y,ll z){
d[x]=d[f[0][x]=y]+1,fm[0][x]=z;
for(int i=1;i<=K;i++)f[i][x]=f[i-1][f[i-1][x]],fm[i][x]=min(fm[i-1][x],fm[i-1][f[i-1][x]]);
for(int i=g[x];i;i=nxt[i])if(v[i]!=y)dfs(v[i],x,w[i]);
}
inline ll ask(int x,int y){
ll t=inf;
if(x==y)return t;
if(d[x]<d[y])swap(x,y);
for(int i=K;~i;i--)if(d[f[i][x]]>=d[y])t=min(t,fm[i][x]),x=f[i][x];
if(x==y)return t;
for(int i=K;~i;i--)if(f[i][x]!=f[i][y])t=min(t,min(fm[i][x],fm[i][y])),x=f[i][x],y=f[i][y];
return min(t,min(fm[0][x],fm[0][y]));
}
inline void read(int&a){
char c;bool f=0;a=0;
while(!((((c=getchar())>='0')&&(c<='9'))||(c=='-')));
if(c!='-')a=c-'0';else f=1;
while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';
if(f)a=-a;
}
int main(){
read(n),read(m),read(q);
for(i=1;i<=n;i++)read(a[i]);
for(i=1;i<=n;i++)read(b[i]);
for(i=1;i<=m;i++)read(e[i].x),read(e[i].y),read(j),e[i].z=j;
for(i=1;i<=q;i++)read(c[i]);
for(i=1;i<q;i++)e[++m].x=c[i],e[m].y=c[q],e[m].z=inf;
for(i=1;i<=n;i++)fa[i]=i;
sort(e+1,e+m+1,cmp);
for(i=1;i<=m;i++)if(F(e[i].x)!=F(e[i].y))fa[fa[e[i].x]]=fa[e[i].y],add(e[i].x,e[i].y,e[i].z);
dfs(1,0,0);
lim[n]=max(0,-b[a[n]]);
for(lim[n]=max(0,-b[a[n]]),i=n-1;i;i--)lim[i]=min(lim[i+1],ask(a[i],a[i+1]))+max(0,-b[a[i]]);
for(i=1;i<=n;i++){
if(b[a[i]]>0)now=min(1LL*(now+b[a[i]]),lim[i]);
else printf("%lld\n",tmp=min(now,-(ll)b[a[i]])),now-=tmp;
}
return 0;
}