poj3417 Network(樹上差分)
阿新 • • 發佈:2018-11-11
題意
給出一棵樹,再給出幾條附加邊,使得樹存在環。求割掉一條主要邊和一條附加邊能讓樹不連通的方案數。
題解
lca+樹上差分
觀察題目中附加邊的特點,連線(x,y)的附加邊使得(x,y)之間的連線方式又增加了1。
不妨設一開始的連線方式為0。一條附加邊可以使(x,y)之間的主要邊的連線方式+1。
如果割一條邊被加到了2或以上,說明割掉這條主要邊之後還得再割兩條附加邊,無法做到。
如果只被加到了1,說明在割掉這條主要邊之後把那條使這條邊+1的附加邊割掉,可以把圖分成兩部分。ans+=1
如果沒有被加過,那麼在割掉這條主要邊之後圖就已經不連通了,再隨意割一條附加邊即可。ans+=m
對於樹上一段連續的邊的加減操作,用樹上差分即可。
程式碼
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=1e5+10,maxm=2e5+10; int bin[30]; int n,m; struct E{int y,next;}e[maxn*2];int len=0,last[maxn]; void ins(int x,int y) { e[++len]=(E){y,last[x]};last[x]=len; } int f[maxn][30];int dep[maxn]; void dfs(int x,int fa) { for(int k=last[x];k;k=e[k].next) { int y=e[k].y; if(y==fa) continue; dep[y]=dep[x]+1; f[y][0]=x; for(int i=1;i<=20;i++) f[y][i]=f[f[y][i-1]][i-1]; dfs(y,x); } } int lca(int x,int y) { if(dep[y]>dep[x]) swap(x,y); for(int i=20;i>=0;i--) if(dep[y]<=dep[x]-bin[i]) x=f[x][i];//debug Ìøx if(x==y) return x; for(int i=20;i>=0;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0]; } int d[maxn];int ans=0; void dfs2(int x,int fa) { for(int k=last[x];k;k=e[k].next) { int y=e[k].y; if(y==fa) continue; dfs2(y,x); d[x]+=d[y]; } if(x==1) return ; if(d[x]==0) ans+=m; else if(d[x]==1) ans++; } int main() { bin[0]=1;for(int i=1;i<=20;i++) bin[i]=1<<i; scanf("%d%d",&n,&m); for(int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); ins(x,y);ins(y,x); } dep[1]=0;dfs(1,0); for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); d[x]++;d[y]++;d[lca(x,y)]-=2;//樹上差分 } dfs2(1,0);//還原實際值並統計方案 printf("%d\n",ans); return 0; }