1. 程式人生 > 其它 >【SCOI2013】摩托車交易 題解

【SCOI2013】摩托車交易 題解

比較簡單的洛谷紫題

【SCOI2013】摩托車交易

Description

mzry1992 在打完吊針出院之後,買了輛新摩托車,開始了在周邊城市的黃金運送生意。
在mzry1992 生活的地方,城市之間是用雙向高速公路連線的,另外,每條高速公路有一個載重上限,即在不考慮駕駛員和摩托車重量的情況下,如果所載貨物的量超過某個值,則不能駛上該條高速公路。
今年,mzry1992 一共收到了來自n個不同城市的n份定訂單,每個訂單要求賣出上限為一定量的黃金,或是要求買入上限為一定量的黃金。由於訂單並不是同時發來的,為了維護生意上的名聲,mzry1992 不得不按照訂單發來的順序與客戶進行交易。
他與第i客戶進行交易的具體步驟是:

  1. 前往第i個客戶所在城市。當然,中途是完全允許經過其他城市的。
  2. 與第i個客戶進行交易。
    但有兩個限制:
    (a) 與最後一個客戶完成交易後,手上沒有剩餘黃金。
    (b) 由於黃金是很貴重的物品,不能出現因為買入過多黃金而造成在以後的運送過程中不得不丟棄黃金的情況。
    mzry希望總交易額最大,其次他希望賣出交易額序列的字典序最大。其中字典序指的是先比較第一次賣出交易額,若相等則比較下一次,以此類推。
    一開始,mzry1992 位於第一個訂單客戶所在的城市。
    現在有一個好訊息,有人提供了mzry1992 免費試用周邊城市的列車系統的資格。具體來講,如果mzry1992希望從A 城市到達B 城市,且A、B 城市均有列車站的話,他可以攜帶著黃金與摩托車從A 城市乘坐列車到B 城市,這裡假定乘坐列車沒有載重限制。
    現在已知城市間的交通系統情況和訂單情況,請幫助mzry1992 計算每個向mzry1992 購買黃金的客戶的購買量。

Input

輸入的第一行有三個整數n, m, q,分別表示城市數,連通城市的高速公路數和有列車站的城市數。
接下來的一行有n 個數,每個數均不相同,且值介於1 到n 之間,代表訂單的順序。
第三行有n 個數,第i 個數表示i 號城市的訂單的上限額bi,bi 為正值表示該訂單為買入交易(針對mzry1992 而言),上限為bi,bi 為負值表示該訂單為賣出交易(同樣針對mzry1992 而言)上限為-bi。
接下來的m 行每行有三個數,u, v, w,表示城市u 和城市v 之間有一條載重上限為w 的高速公路,這裡假定所有高速公路都是雙向的,城市的序號是從1 到n 的。
輸入的最後一行有q 個數,代表有列車站城市的序號。

Output

按照訂單順序對於每個賣出交易,輸出一行,該行只有一個整數x,表示賣出黃金的量。

Sample Input

輸入1:
3 3 2
2 3 1
-6 5 -3
1 3 5
2 3 2
2 1 6
1 3
輸入2:
4 4 0
1 2 3 4
5 4 -6 -1
1 2 4
2 3 100
3 4 1
4 1 4

Sample Output

輸出1:
3
2
樣例解釋1:
其中一種合法的方案是最初從2 號城市買入5 單位的黃金,先走第三條高速公路到1 號城市,然後再坐列車到3 號城市,在3 號城市賣出3 單位的黃金,然後乘坐列車到1 城市,在1 號城市賣出2 單位的黃金。
輸出2:
6
1
樣例解釋2:
其中一種合法的方案是最初從1 號城市買入4 單位的黃金,走第一條高速公路,在2 號城市買入3 單位的黃金,走第二條高速公路,在三城市點賣出6 單位的黃金,走第三條高速公路,在4 號城市賣出1 單位的黃金。

Data Constraint

對於20% 資料,n<=100,m<=200
對於50% 資料,n<=3000,m<=6000
對於100% 資料,1<=n<=105,n-1<=m<=2*105,0<=q<=n,0<|bi|<109,0<w<109,保證任意兩個城市之間是通過高速公路連通的。

題解

顯然,這題的買賣黃金過程很用模擬就可以實現,關鍵是可以買賣多少
首先需要明確一點,就是我們不一定要按照題目說的不能丟棄黃金,其實可以全部買完,之後在過不去路的時候再丟掉,這樣子是對答案沒有影響的
然後買賣黃金的過程就相當於是一個貪心了,需要買的城市全部買來,需要賣的城市能賣多少賣多少
下一個重要點就是找到一個城市到另一個城市中負重最小的邊(因為兩個城市間可以攜帶的黃金的量是由負重最小的那條邊決定的),然後因為要運儘量多黃金,所以我們就要讓最小的那條邊的負重最大
所以我們可以想到什麼?最大生成樹!
於是我們只要保留原圖中屬於最生成樹的邊即可(至於列車站怎麼連邊,其實只要相鄰地連過來就行了,因為最後形成的是一棵樹)
接著,要在樹上找到路徑邊權的最小值就隨便用什麼方法找都行了,可以用求LCA的方式,我用的是倍增,大佬用樹剖和Tarjan也行

CODE

#include<cstdio>
#include<string>
#include<cmath>
#include<algorithm>
#define max(a,b) (((a)>(b))?(a):(b))
#define min(a,b) (((a)<(b))?(a):(b))
#define swap(a,b) (a)^=(b)^=(a)^=(b)
#define R register ll
#define N 100005
#define M 300005
#define ll long long
#define inf 100000000000
using namespace std;
struct arr{ll u,v,w;}bian[M];
struct G{ll to,next,w;}e[N<<1];
ll n,m,q,go[N],train[N],tot,fa[N],cnt,f[N][20],dep[N],mxdep,head[N],b[N],g[N][20];;
inline void read(ll &x)
{
	x=0;ll f=1;char ch=getchar();
	while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
	while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();x*=f;
}
inline bool cmp(arr x,arr y) {return x.w>y.w;}
inline void add(ll u,ll v,ll len)
{
	e[++cnt].to=v;e[cnt].w=len;
	e[cnt].next=head[u];head[u]=cnt;
}
inline void dfs(ll u,ll fa)
{
	for (R i=head[u];i;i=e[i].next)
	{
		ll v=e[i].to;if (v==fa) continue;
		f[v][0]=u;g[v][0]=e[i].w;dep[v]=dep[u]+1;mxdep=max(dep[v],mxdep);dfs(v,u);
	}
}
inline ll lca(ll x,ll y)
{
	ll mn=inf;
	if (dep[x]!=dep[y])
	{
		if (dep[x]<dep[y]) swap(x,y);
		for (R i=log2(dep[x]-dep[y]);i>=0;--i)
			if (dep[f[x][i]]>dep[y]) mn=min(g[x][i],mn),x=f[x][i];
		mn=min(g[x][0],mn);x=f[x][0];	
	}
	if (x==y) return mn;
	for (R i=log2(dep[x]);i>=0;--i)
		if (f[x][i]!=f[y][i]) mn=min(mn,min(g[x][i],g[y][i])),x=f[x][i],y=f[y][i];
	mn=min(mn,min(g[x][0],g[y][0]));return mn; 
}
inline ll find(ll k)
{
	if (fa[k]==k) return k;return fa[k]=find(fa[k]);
}
int main()
{
	read(n);read(m);read(q);
	for (R i=1;i<=n;++i)
		read(go[i]),fa[i]=i;
	for (R i=1;i<=n;++i)
		read(b[i]);
	for (R i=1;i<=m;++i)
		read(bian[i].u),read(bian[i].v),read(bian[i].w);
	for (R i=1;i<=q;++i)
	{
		read(train[i]);
		if (i>1) bian[++m].u=train[i-1],bian[m].v=train[i],bian[m].w=inf;
	}
	sort(bian+1,bian+1+m,cmp);ll tot=1;
	for (R i=1;i<=m;++i)
	{
		ll f1=find(bian[i].u),f2=find(bian[i].v);
		if (f1!=f2)
		{
			add(bian[i].u,bian[i].v,bian[i].w);
			add(bian[i].v,bian[i].u,bian[i].w);
			++tot;fa[f1]=f2;if (tot==n) break;
		}
	}
	mxdep=1;dep[1]=1;dfs(1,0);
	for (R j=1;j<=log2(mxdep);++j)
		for (R i=1;i<=n;++i)
			f[i][j]=f[f[i][j-1]][j-1],g[i][j]=min(g[i][j-1],g[f[i][j-1]][j-1]);
	ll now=go[1];tot=0;
	if (b[go[1]]>0) tot=b[go[1]];else printf("0\n");
	for (R i=2;i<=n;++i)
	{
		ll k=lca(go[i-1],go[i]);
		if (tot>k) tot=k;
		if (b[go[i]]>0) tot+=b[go[i]];
		else
		{
			printf("%lld\n",min(-b[go[i]],tot));
			tot-=min(-b[go[i]],tot);
		}
	}
	return 0;
}