1. 程式人生 > >洛谷 P3128 [USACO15DEC]最大流Max Flow-樹上差分(點權)(模板題)

洛谷 P3128 [USACO15DEC]最大流Max Flow-樹上差分(點權)(模板題)

因為徐州現場賽的G是樹上差分+組合數學,但是比賽的時候沒有寫出來(自閉),背鍋。

會差分陣列但是不會樹上差分,然後就學了一下。

看了一些東西之後,對樹上差分寫一點個人的理解:

 

首先要知道在樹上,兩點之間只有一條路徑。樹上差分就是在樹上用差分陣列,因為是在樹上的操作,所以要用到lca,因為對於兩點a,b,從a到b這一條鏈就是a-->lca(a,b)-->b,這是一條鏈。

其次,樹上差分的兩種操作:一種是對點權的,另一種是對邊權的。

對於點權:

在樹上將路徑的起點a+1和終點b+1,lca(a,b)-1,lca(a,b)的爸爸-1,因為對於點權,從a到b包括lca(a,b),因為lca其實是+2,lca(a,b)多算了一次,所以lca(a,b)-1,但是lca(a,b)往上的爸爸們都沒有計算到,所以lca的爸爸-1就可以。總的程式碼就是

sum[a]++;sum[b]++;sum[lca]--;sum[fa[lca][0]]--;

對於邊權:

在樹上,對於a和b,用深度更深的那個數表示邊的編號,對於a和b連線的邊,如果a是b的爸爸,那麼這條邊的編號就是b。

在樹上將起點邊a+1,終點邊b+1,lca(a,b)-2,因為對於邊權,從邊a到邊b,不包括lca(a,b),因為lca(a,b)這一條邊並不在從a到b的路徑上,但是lca(a,b)其實多算了2次,所以要減去,就是lca(a,b)-2。

程式碼就是

sum[a]++;sum[b]++;sum[lca]-=2;

 

其他的好像也沒什麼了,就是dfs的時候別寫撈了就可以。

先貼一個關於點權的樹上差分。

 

P3128 [USACO15DEC]最大流Max Flow

題目描述

Farmer John has installed a new system of N-1N1 pipes to transport milk between the NN stalls in his barn (2 \leq N \leq 50,0002N50,000), conveniently numbered 1 \ldots N1N. Each pipe connects a pair of stalls, and all stalls are connected to each-other via paths of pipes.

FJ is pumping milk between KK pairs of stalls (1 \leq K \leq 100,0001K100,000). For the iith such pair, you are told two stalls s_isi and t_iti, endpoints of a path along which milk is being pumped at a unit rate. FJ is concerned that some stalls might end up overwhelmed with all the milk being pumped through them, since a stall can serve as a waypoint along many of the KK paths along which milk is being pumped. Please help him determine the maximum amount of milk being pumped through any stall. If milk is being pumped along a path from s_isi to t_iti, then it counts as being pumped through the endpoint stalls s_isi and

t_iti, as well as through every stall along the path between them.

FJ給他的牛棚的N(2≤N≤50,000)個隔間之間安裝了N-1根管道,隔間編號從1到N。所有隔間都被管道連通了。

FJ有K(1≤K≤100,000)條運輸牛奶的路線,第i條路線從隔間si運輸到隔間ti。一條運輸路線會給它的兩個端點處的隔間以及中間途徑的所有隔間帶來一個單位的運輸壓力,你需要計算壓力最大的隔間的壓力是多少。

輸入輸出格式

輸入格式:

 

The first line of the input contains NN and KK.

The next N-1N1 lines each contain two integers xx and yy (x \ne yxy) describing a pipe

between stalls xx and yy.

The next KK lines each contain two integers ss and tt describing the endpoint

stalls of a path through which milk is being pumped.

 

輸出格式:

 

An integer specifying the maximum amount of milk pumped through any stall in the

barn.

 

輸入輸出樣例

輸入樣例#1:  複製
5 10
3 4
1 5
4 2
5 4
5 4
5 4
3 5
4 3
4 3
1 3
3 5
5 4
1 5
3 4
輸出樣例#1:  複製
9

 

 

題目就是關於點權的,樹上差分的模板題。直接程式碼。

 

程式碼:

 1 //洛谷 P3128 [USACO15DEC]最大流Max Flow -樹上差分(點的樹上差分)
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<bitset>
 7 #include<cassert>
 8 #include<cctype>
 9 #include<cmath>
10 #include<cstdlib>
11 #include<ctime>
12 #include<deque>
13 #include<iomanip>
14 #include<list>
15 #include<map>
16 #include<queue>
17 #include<set>
18 #include<stack>
19 #include<vector>
20 using namespace std;
21 typedef long long ll;
22 typedef pair<int,int> pii;
23 
24 const double PI=acos(-1.0);
25 const double eps=1e-6;
26 const ll mod=1e9+7;
27 const int inf=0x3f3f3f3f;
28 const int maxn=1e5+10;
29 const int maxm=100+10;
30 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
31 
32 struct node{
33     int to,next;
34 }edge[maxn<<2];
35 
36 int head[maxn<<2],sum[maxn],dep[maxn],fa[maxn][30],n,m,cnt,ans;
37 
38 int read()//加速掛
39 {
40     int res=0;
41     char c=getchar();
42     while(c<'0'||c>'9') c=getchar();
43     while(c>='0'&&c<='9') res=res*10+c-'0',c=getchar();
44     return res;
45 }
46 
47 void add(int x,int y){edge[++cnt].to=y,edge[cnt].next=head[x],head[x]=cnt;}//鏈式前向星存圖
48 
49 void dfs(int u,int fath)
50 {
51     dep[u]=dep[fath]+1,fa[u][0]=fath;
52     for (int i=0;fa[u][i];++i) fa[u][i+1]=fa[fa[u][i]][i];
53     for (int i=head[u];i;i=edge[i].next){
54         int v=edge[i].to;
55         if(v!=fath) dfs(v,u);
56     }
57 }
58 
59 int LCA(int u,int v)
60 {
61     if(dep[u]>dep[v]) swap(u,v);
62     for (int i=20;i>=0;--i) if(dep[u]<=dep[v]-(1<<i)) v=fa[v][i];
63     if(u==v) return u;
64     for (int i=20;i>=0;--i) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
65     return fa[u][0];
66 }
67 
68 void Dfs(int u,int fath)//最後的遍歷操作
69 {
70     for (int i=head[u];i;i=edge[i].next){
71         int v=edge[i].to;
72         if(v==fath) continue;
73         Dfs(v,u);
74         sum[u]+=sum[v];
75     }
76     ans=max(ans,sum[u]);
77 }
78 
79 int main()
80 {
81     n=read(),m=read();
82     int x,y;
83     for (int i=1;i<n;i++){
84         x=read(),y=read();
85         add(x,y);add(y,x);
86     }
87     dfs(1,0);
88     for (int i=1;i<=m;++i){
89         x=read();y=read();
90         int lca=LCA(x,y);
91         ++sum[x];++sum[y];--sum[lca];--sum[fa[lca][0]];
92     }
93     Dfs(1,0);
94     printf("%d\n",ans);
95     return 0;
96 }

 

 

溜了,本來昨天就改寫的,忘了。