EOJ Monthly 2018.8 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 n1 bi-directional paths connecting them, forming a tree. The length of the i-th path is wi, meaning that the time we have to spend walking through this path is wi.

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 (1n2105).

The next n1 lines tell about the path information from path 1 to path n1, the i-th of which contains three space-separated integers uivi and wi (1ui,vinuivi1wi1000).

The next line contains one integer q (1q2105).

The next q lines each contains two space-separated integers si and ti (1si,tin,siti).

输出

Output one integer, the minimum total time you can achieve.

样例

input
5
1 2 2
1 3 3
3 4 3
3 5 4
2
1 5
4 2
output
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 }

溜了。。。

原文地址:https://www.cnblogs.com/ZERO-/p/9985722.html