HDU - 5452 Minimum Cut(LCA+树上差分)
題目鏈接:點擊查看
題目大意:給出n個點,n-1條邊組成一棵樹,然后再給出m-n-1條邊,組成一個圖,現在要讓我們求最少刪去幾條邊才能讓整個圖不連通,并且要求只能在樹上刪去最多一條邊
題目分析:這個題目的意思有點難懂,大概就是需要刪邊,刪去最少的邊讓整個圖不連通,當我們在一棵樹上繼續加邊的話,必定會形成環,假如我們想讓u-v這里出現斷點,那么我們就需要將u-v這條邊在樹上刪去,然后再將與u和v形成環的邊全部刪除才行,舉個例子,借網上大佬的一組圖方便理解:
?上面這個圖中,實線是樹,虛線是邊,這樣組成了一個圖,若我們想讓2-5出現斷點,則首先必須刪去2-5這條邊,然后再將3-5這條邊刪除,若我們想讓1-2出現斷點,則也是應該先刪去1-2這條邊,然后再刪去3-5這條邊,同理,若我們想讓1-5出現斷點,應該刪去2-5或1-2,同時刪去3-5
?下面這個圖也是一樣的道理,我們可以看出,在樹上增加一條邊u-v,則這條邊會影響到樹上u-v這條路徑上的所有邊
綜上所述,我們就可以在讀入m-n-1條邊的時候,對于u-v這條路徑上的權值維護一下就好了,一開始是想將邊權映射到點權上去,然后用線段樹+樹鏈剖分來維護權值,最后求一下每個點權值取一個最小值就好了,但這樣的話會被這個題卡超時,無奈,只能換一種方法,鯤學長之前提示過,于是我就換成樹上差分來寫這個題,因為dfs序前序遍歷的原因,讓u-lca和lca-v這條邊上的序號是連續的,這樣就可以用樹上差分了,最后在樹上自底向上跑一遍前綴和,然后再跑一邊最小值答案就出來了
不過需要注意一下,這個答案是需要刪掉m-n-1中的多少條邊,還要在最小生成樹中刪去相應的邊,所以最終答案記得加一
對了,需要注意一下:
這個題目是對邊權差分,采用第一種公式即可
代碼:
#include<iostream> #include<cstdlib> #include<string> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<cmath> #include<cctype> #include<stack> #include<queue> #include<list> #include<vector> #include<set> #include<map> #include<sstream> #include<unordered_map> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=2e4+100;int n,m,limit;vector<int>node[N];int val[N],sum[N];int dp[N][20],deep[N];void dfs(int u,int f,int dep) {deep[u]=dep;dp[u][0]=f;for(int i=1;i<=limit;i++)dp[u][i]=dp[dp[u][i-1]][i-1];for(auto v:node[u]){if(v==f)continue;dfs(v,u,dep+1);} }int LCA(int a,int b) {if(deep[a]<deep[b])swap(a,b);for(int i=limit;i>=0;i--)if(deep[a]-deep[b]>=(1<<i))a=dp[a][i];if(a==b)return a;for(int i=limit;i>=0;i--)if(dp[a][i]!=dp[b][i]){a=dp[a][i];b=dp[b][i];}return dp[a][0]; }void dfs2(int u,int f) {sum[u]=val[u];for(auto v:node[u]){if(v==f)continue;dfs2(v,u);sum[u]+=sum[v];} }void init() {memset(val,0,sizeof(val));for(int i=1;i<=n;i++)node[i].clear();limit=log2(n)+1; }int main() { // freopen("input.txt","r",stdin); // ios::sync_with_stdio(false);int w;cin>>w;int kase=0;while(w--) {scanf("%d%d",&n,&m);init();m-=n-1;for(int i=1;i<n;i++){int u,v;scanf("%d%d",&u,&v);node[u].push_back(v);node[v].push_back(u);}dfs(1,0,0);while(m--){int u,v;scanf("%d%d",&u,&v);val[u]++;val[v]++;val[LCA(u,v)]-=2;}dfs2(1,0);int ans=inf;for(int i=2;i<=n;i++)ans=min(ans,sum[i]);printf("Case #%d: %d\n",++kase,ans+1); }return 0; }?
總結
以上是生活随笔為你收集整理的HDU - 5452 Minimum Cut(LCA+树上差分)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HDU - 6203 ping ping
- 下一篇: Gym - 101889I Imperi