题解 P3280 【[SCOI2013]摩托车交易 】

· · 题解

P3280 [SCOI2013]摩托车交易

题意

题解

$~~~~$ 先来看两个限制怎么解决,由于买入的时候不需要输出,其实我们完全可以全部买下来,然后在路上丢掉。(其实丢掉多少就是少买多少)所以直接忽略限制(b) 即可。然后你会发现限制(a)也可以用这样的方法忽略掉,所以我们每次买入直接全买就可以了。~~所以这两个限制完全就是来干扰的。~~ $~~~~$ 再来看剩下的部分,两种道路,有限制时我们可以想到 [P1967 货车运输](https://www.luogu.com.cn/problem/P1967 "路径上权值最小值最大") ,用 Kruskal重构树 将权值从大到小排序即可。至于没有限制时,我们完全可以转化为其限制为无限大(本题的 $INF$ 开到 $10^9$ 即可),那就又变成第一种了。 $~~~~$ 所以这道题就解决了。注意数组要开够大,有时候它不够会爆 `WA` 而不是 `RE`. --- #### 代码 ```cpp #include <cstdio> #include <vector> #include <algorithm> #define ll long long using namespace std; const ll INF=1e18; ll n,m,p; ll tot,fa[400005],order[400005],gold[400005]; vector <ll> G[400005]; struct Edge{ ll u,v; ll w; Edge(){} Edge(ll U,ll V,ll W){u=U,v=V,w=W;} }E[600005]; ll findSet(ll x) { if(fa[x]==x) return x; else return fa[x]=findSet(fa[x]); } void Kru() { ll cnt=0; for(ll i=1;i<=m+max(p,1ll)-1;i++) { ll u=E[i].u,v=E[i].v,w=E[i].w; u=findSet(u),v=findSet(v); if(u!=v) { tot++;cnt++; gold[tot]=w; G[u].push_back(tot); G[tot].push_back(u); fa[u]=tot; G[v].push_back(tot); G[tot].push_back(v); fa[v]=tot; } if(cnt==n-1) return; } } inline bool cmp(Edge x,Edge y){return x.w>y.w;} ll dep[400005],f[400005][20],lg[400005]; void dfs(ll u,ll fat) { dep[u]=dep[fat]+1; f[u][0]=fat; for(ll i=1;i<=lg[dep[u]];i++) f[u][i]=f[f[u][i-1]][i-1]; for(ll i=0;i<G[u].size();i++) { ll v=G[u][i]; if(v==fat) continue; dfs(v,u); } } ll query(ll x,ll y) { if(dep[x]<dep[y]) swap(x,y); while(dep[x]>dep[y]) x=f[x][lg[dep[x]-dep[y]]-1]; if(x==y) return gold[x]; for(ll k=lg[dep[x]]-1;k>=0;k--) { if(f[x][k]!=f[y][k]) x=f[x][k],y=f[y][k]; } return gold[f[x][0]]; } int main() { ll root; scanf("%lld %lld %lld",&n,&m,&p); for(ll i=1;i<=n;i++) fa[i]=i,lg[i]=lg[i-1]+(1<<lg[i-1]==i),scanf("%lld",&order[i]); for(ll i=1;i<=n;i++) fa[i+n]=i+n,lg[i+n]=lg[i+n-1]+(1<<lg[i+n-1]==i+n),scanf("%lld",&gold[i]); for(ll i=1,u,v,w;i<=m;i++) { scanf("%lld %lld %lld",&u,&v,&w); E[i]=Edge(u,v,w); } if(p) scanf("%lld",&root); for(ll i=1,q;i<p;i++) { scanf("%lld",&q); E[m+i]=Edge(root,q,INF); } tot=n; sort(E+1,E+m+max(p,1ll),cmp); Kru(); dfs(tot,0); ll now=gold[order[1]]; if(now<=0) puts("0"),now=0; for(ll i=1;i<n;i++) { ll x=order[i],y=order[i+1]; ll re=query(x,y); now=min(now,re); if(gold[y]>0) now+=gold[y]; else { if(now+gold[y]>=0) printf("%lld\n",-gold[y]),now+=gold[y]; else printf("%lld\n",now),now=0; } } return 0; } ```