hdu5452 樹上差分
阿新 • • 發佈:2020-11-17
hdu5452 Minimum Cut
傳送門
題意
有一個包含\(n(2\leq n\leq 20000)\)個點,\(m(n-1\leq m\leq 200000)\)條邊的無向圖,其中前\(n-1\)條邊是樹邊。刪除一些邊,並且其中只能包含一條樹邊,使得圖不連通,計算最少刪掉的邊數
題解
除了樹邊之外,每加一條邊就會多形成一個環,對於環內的樹邊來說,刪除其中一條使得圖不連通的所要刪除的總邊數加一,也就是說每條非樹邊都對環內樹邊產生貢獻。如果非樹邊所連線的兩個頂點是\(u\)和\(v\),那麼這條邊對於從\(u\)到\(v\)的路徑上的樹邊都會增加1的貢獻,通過樹上差分統計所有非樹邊的貢獻,最後計算樹邊邊權的最小值
#include<iostream> #include<cstdio> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<cstring> #include<string> #include<sstream> #include<cmath> #include<ctime> #include<climits> #include<algorithm> #define LL long long #define PII pair<int,int> #define PLL pair<LL,LL> #define pi acos(-1.0) #define eps 1e-6 #define lowbit(x) x&(-x) using namespace std; const int maxn=20010,maxm=40010; int T,n,m; int head[maxn],nxt[maxm],to[maxm],cnt; int depth[maxn],fa[maxn][20]; int diff[maxn],ans[maxn]; void add(int u,int v){ to[cnt]=v; nxt[cnt]=head[u]; head[u]=cnt++; } void dfs(int u,int f){ fa[u][0]=f; for(int i=head[u];~i;i=nxt[i]){ int v=to[i]; if(v!=f){ depth[v]=depth[u]+1; dfs(v,u); } } } void lca_init(){ depth[1]=1; dfs(1,0); for(int j=1;j<=15;j++){ for(int i=1;i<=n;i++){ fa[i][j]=fa[fa[i][j-1]][j-1]; } } } int lca(int x,int y){ if(depth[x]>depth[y]) swap(x,y); int d=depth[y]-depth[x]; for(int i=0;i<=15;i++){ if((1<<i)&d) y=fa[y][i]; } if(x==y) return x; for(int i=15;i>=0;i--){ if(fa[x][i]!=fa[y][i]){ x=fa[x][i]; y=fa[y][i]; } } return fa[x][0]; } void dfs2(int u,int f){ ans[u]=diff[u]; for(int i=head[u];~i;i=nxt[i]){ int v=to[i]; if(v==f) continue; dfs2(v,u); ans[u]+=ans[v]; } } int main(){ scanf("%d",&T); for(int cas=1;cas<=T;cas++){ scanf("%d%d",&n,&m); memset(head,-1,sizeof(head)); cnt=0; for(int i=1;i<n;i++){ int x,y; scanf("%d%d",&x,&y); add(x,y); add(y,x); } lca_init(); memset(diff,0,sizeof(diff)); for(int i=n;i<=m;i++){ int x,y; scanf("%d%d",&x,&y); int t=lca(x,y); diff[x]++; diff[y]++; if(t!=1) diff[t]-=2; } dfs2(1,0); int res=2e9+10; for(int i=1;i<=n;i++) res=min(res,ans[i]+1); printf("Case #%d: %d\n",cas,res); } return 0; }