HDU - 5452 Minimum Cut(LCA+树上差分)
題目鏈接:點(diǎn)擊查看
題目大意:給出n個(gè)點(diǎn),n-1條邊組成一棵樹,然后再給出m-n-1條邊,組成一個(gè)圖,現(xiàn)在要讓我們求最少刪去幾條邊才能讓整個(gè)圖不連通,并且要求只能在樹上刪去最多一條邊
題目分析:這個(gè)題目的意思有點(diǎn)難懂,大概就是需要?jiǎng)h邊,刪去最少的邊讓整個(gè)圖不連通,當(dāng)我們在一棵樹上繼續(xù)加邊的話,必定會形成環(huán),假如我們想讓u-v這里出現(xiàn)斷點(diǎn),那么我們就需要將u-v這條邊在樹上刪去,然后再將與u和v形成環(huán)的邊全部刪除才行,舉個(gè)例子,借網(wǎng)上大佬的一組圖方便理解:
?上面這個(gè)圖中,實(shí)線是樹,虛線是邊,這樣組成了一個(gè)圖,若我們想讓2-5出現(xiàn)斷點(diǎn),則首先必須刪去2-5這條邊,然后再將3-5這條邊刪除,若我們想讓1-2出現(xiàn)斷點(diǎn),則也是應(yīng)該先刪去1-2這條邊,然后再刪去3-5這條邊,同理,若我們想讓1-5出現(xiàn)斷點(diǎn),應(yīng)該刪去2-5或1-2,同時(shí)刪去3-5
?下面這個(gè)圖也是一樣的道理,我們可以看出,在樹上增加一條邊u-v,則這條邊會影響到樹上u-v這條路徑上的所有邊
綜上所述,我們就可以在讀入m-n-1條邊的時(shí)候,對于u-v這條路徑上的權(quán)值維護(hù)一下就好了,一開始是想將邊權(quán)映射到點(diǎn)權(quán)上去,然后用線段樹+樹鏈剖分來維護(hù)權(quán)值,最后求一下每個(gè)點(diǎn)權(quán)值取一個(gè)最小值就好了,但這樣的話會被這個(gè)題卡超時(shí),無奈,只能換一種方法,鯤學(xué)長之前提示過,于是我就換成樹上差分來寫這個(gè)題,因?yàn)閐fs序前序遍歷的原因,讓u-lca和lca-v這條邊上的序號是連續(xù)的,這樣就可以用樹上差分了,最后在樹上自底向上跑一遍前綴和,然后再跑一邊最小值答案就出來了
不過需要注意一下,這個(gè)答案是需要?jiǎng)h掉m-n-1中的多少條邊,還要在最小生成樹中刪去相應(yīng)的邊,所以最終答案記得加一
對了,需要注意一下:
這個(gè)題目是對邊權(quán)差分,采用第一種公式即可
代碼:
#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; }?
總結(jié)
以上是生活随笔為你收集整理的HDU - 5452 Minimum Cut(LCA+树上差分)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HDU - 6203 ping ping
- 下一篇: Gym - 101889I Imperi