1. 程式人生 > >【洛谷P3128】最大流

【洛谷P3128】最大流

pac ostream include 分享 def mes std string tchar

本題當然可以用樹剖解決,而且是樹剖的模板題。但是對於本題來說,有一種更巧妙的辦法

樹上差分

類似於普通的差分,我們對於題目中的每一條路線i->j,把它拆成i->lca(i,j)->j.然後將i點、j點的權值加一,將lca(i,j)的權值減二

乍看起來沒什麽毛病,但是仔細想想,對lca(i,j)的子樹進行前綴和,則lca(i,j)點的權值加二又減二,而題目要求lca(i,j)權值應當+1

所以我們將lca(i,j)的權值減一,將lca(i,j)的父親的權值減一,這樣就能符合題意了

差分之前預處理每個點的祖先,LCA+差分即可

技術分享圖片
 1 #include <iostream>
 2
#include <cstdio> 3 #include <cstring> 4 typedef long long ll; 5 inline int read() { 6 int ret=0,f=1; 7 char c=getchar(); 8 while(c<0||c>9) {if(c==-) f=-1;c=getchar();} 9 while(c<=9&&c>=0) ret=ret*10+c-0,c=getchar(); 10 return
ret*f; 11 } 12 using namespace std; 13 int n,k; 14 struct edge { 15 int next,to; 16 }a[50010<<1]; 17 int num,head[50010<<1]; 18 int sum[50010],ans; 19 int d[50010],fa[50010][31]; 20 inline void add(int from,int to) { 21 a[++num].next=head[from]; a[num].to=to; head[from]=num; 22 swap(from
,to); 23 a[++num].next=head[from]; a[num].to=to; head[from]=num; 24 } 25 void find(int u,int f) { 26 d[u]=d[f]+1; 27 fa[u][0]=f; 28 for(int i=0;i<30;i++) fa[u][i+1]=fa[fa[u][i]][i]; 29 for(int i=head[u];i;i=a[i].next) { 30 int v=a[i].to; 31 if(v==f) continue ; 32 find(v,u); 33 } 34 } 35 int lca(int x,int y) { 36 if(d[x]<d[y]) swap(x,y); 37 for(int i=30;i>=0;i--) { 38 if(d[fa[x][i]]>=d[y]) x=fa[x][i]; 39 if(x==y) return x; 40 } 41 for(int i=30;i>=0;i--) 42 if(fa[x][i]!=fa[y][i]) { 43 x=fa[x][i]; 44 y=fa[y][i]; 45 } 46 return fa[x][0]; 47 } 48 void dfs(int u,int f) { 49 for(int i=head[u];i;i=a[i].next) { 50 int v=a[i].to; 51 if(v==f) continue ; 52 dfs(v,u); 53 sum[u]+=sum[v]; 54 } 55 ans=max(ans,sum[u]); 56 } 57 int main() { 58 n=read(); k=read(); 59 for(int i=1;i<n;i++) add(read(),read()); 60 find(1,0); 61 for(int i=1;i<=k;i++) { 62 int x=read(),y=read(); 63 sum[x]++; 64 sum[y]++; 65 int ret=lca(x,y); 66 sum[ret]--; 67 sum[fa[ret][0]]--; 68 } 69 dfs(1,0); 70 printf("%d\n",ans); 71 return 0; 72 }
AC Code

【洛谷P3128】最大流