EOJ Monthly 2018.8 D. Delivery Service-樹上差分(邊權/邊覆蓋)(邊權轉點權)(模板題)
D. Delivery Service
單測試點時限: 2.5 秒
記憶體限制: 512 MB
EOJ Delivery Service Company handles a massive amount of orders in our nation. As is well known, our nation has ncities, with n−1 bi-directional paths connecting them, forming a tree. The length of the i
Now, you, as the headquarter of EOJ, has somehow learned a magic spell. Each time you cast a spell on two paths, the lengths of these two paths magically swap with each other. You can do this magic as many times as you want(possibly none).
We have q orders waiting to be handled. The i-th order demands sending a package from city si to city ti. We kindly ask you to do your magic before all the deliveries start, such that the total time we have to spend on delivering these packages is minimized.
輸入
The first line of the input contains one single integer n (1≤n≤2⋅105).
The next n−1 lines tell about the path information from path 1 to path n−1, the i-th of which contains three space-separated integers ui, vi and wi (1≤ui,vi≤n, ui≠vi, 1≤wi≤1000).
The next line contains one integer q (1≤q≤2⋅105).
The next q lines each contains two space-separated integers si and ti (1≤si,ti≤n,si≠ti).
輸出
Output one integer, the minimum total time you can achieve.
樣例
input5 1 2 2 1 3 3 3 4 3 3 5 4 2 1 5 4 2output
14
提示
In the example, we swap the weights between edge (1,2) and (1,3), so that the first order takes 2+4=6 time units to complete; the second order takes 2+3+3=8 time units. Thus the total time is 14.
題意就是給你一棵樹,給你邊(雙向路徑)和邊權,邊權是走這條路要花的時間,你有神奇的能力,可以交換任意兩條邊的邊權,並且你可以無數次使用你的能力。然後給你m對點,表示要走路徑<a,b>,要求你只能在他們開始走之前使用你的能力,問走完之後要花的最少時間是多少。
因為是走之前使用能力,所以可以提前處理出來,所以可以樹上差分,所以樹上差分,對邊覆蓋,把所有要走的路徑先處理一下,sum[a]++,sum[b]++,sum[lca]-=2;然後Dfs遍歷,求出來每條邊走的次數,然後排個序,走的最多的路給最小的邊權,就可以了。
程式碼:
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 #include<algorithm> 6 #include<cstdlib> 7 using namespace std; 8 typedef long long ll; 9 const int maxn=2e5+10; 10 11 struct node{ 12 int to,next; 13 }edge[maxn<<2]; 14 15 bool cmp(int a,int b) 16 { 17 return a>b; 18 } 19 int head[maxn<<2],sum[maxn],dep[maxn],fa[maxn][30],n,m,cnt,ans; 20 21 void add(int x,int y){edge[++cnt].to=y,edge[cnt].next=head[x],head[x]=cnt;} 22 23 void dfs(int u,int fath)//第一遍dfs,把資訊處理出來 24 { 25 dep[u]=dep[fath]+1,fa[u][0]=fath; 26 for(int i=0;fa[u][i];++i) fa[u][i+1]=fa[fa[u][i]][i]; 27 for(int i=head[u];i;i=edge[i].next){ 28 int v=edge[i].to; 29 if(v!=fath) dfs(v,u); 30 } 31 } 32 33 int LCA(int u,int v)//LCA 34 { 35 if(dep[u]>dep[v]) swap(u,v); 36 for(int i=21;i>=0;i--) if(dep[u]<=dep[v]-(1<<i)) v=fa[v][i]; 37 if(u==v) return u; 38 for(int i=21;i>=0;i--) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i]; 39 return fa[u][0]; 40 } 41 42 void Dfs(int u,int fath)//遍歷求和 43 { 44 for(int i=head[u];i;i=edge[i].next){ 45 int v=edge[i].to; 46 if(v==fath) continue; 47 Dfs(v,u); 48 sum[u]+=sum[v]; 49 } 50 } 51 52 int w[maxn]; 53 54 int main() 55 { 56 int n; 57 scanf("%d",&n); 58 for(int i=1;i<n;i++){ 59 int x,y,v; 60 scanf("%d%d%d",&x,&y,&v); 61 add(x,y);add(y,x); 62 w[i]=v; 63 } 64 dfs(1,0); 65 int q; 66 scanf("%d",&q); 67 for(int i=1;i<=q;i++){ 68 int x,y; 69 scanf("%d%d",&x,&y); 70 int lca=LCA(x,y); 71 sum[x]++;sum[y]++;sum[lca]-=2; 72 } 73 Dfs(1,0); 74 sort(w+1,w+1+n-1); 75 sort(sum+1,sum+n+1,cmp); 76 ll ans=0; 77 for(int i=1;i<n;i++){ 78 ans+=(ll)w[i]*sum[i]; 79 } 80 cout<<ans<<endl; 81 }
溜了。。。