思路:
考虑加入新边对原图的影响:
每加入一条边,相当于在原图中构成一个环,因此要使原图在这个环上断开,必须删去这条新边和环上任意一条树边。
统计每一条树边出现在多少个环中,计作$c$:
1.$c=0$,则该边不属于任何一个环,因此删去这条边的同时删去任意一条新边即可,对答案的贡献是$m$;
2.$c=1$,则该边仅属于一个环,因此删去这条边并删去该环上的新边即可,对答案的贡献是$1$;
3.$c\geq 2$,则该边同时包含于多个环中,无论删去哪一个新边,总有别的环使原图连通,对答案的贡献是$0$。
因此我们可以统计$c$来得到答案。
我们可以利用树上差分的思想,对于每条新边$(u,v)$,$f_u=f_u+1$,$f_v=f_v+1$,$f_{LCA(u,v)}=f_{LCA(u,v)}+1$。
最后用树形DP求出每条边被环包含的次数。
Tarjan求LCA。
但是在OJ上测会TLE,必须要把vector改成前向星才可以。
1 #include<cstdio> 2 #include<cctype> 3 inline int getint() { 4 char ch; 5 while(!isdigit(ch=getchar())); 6 int x=ch^‘0‘; 7 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^‘0‘); 8 return x; 9 } 10 const int root=1,nil=0; 11 const int V=100001; 12 struct Edge { 13 int to,next; 14 }; 15 int sz=0; 16 Edge edge[V<<2]; 17 int e[V]={0},q[V]={0}; 18 inline void add_edge(const int u,const int v) { 19 edge[++sz]=(Edge){v,e[u]}; 20 e[u]=sz; 21 } 22 inline void add_query(const int u,const int v) { 23 edge[++sz]=(Edge){v,q[u]}; 24 q[u]=sz; 25 } 26 class DisjointSet { 27 private: 28 int anc[V]; 29 public: 30 DisjointSet() { 31 for(int i=0;i<V;i++) anc[i]=i; 32 } 33 int Find(const int x) { 34 return x==anc[x]?x:anc[x]=Find(anc[x]); 35 } 36 void Union(const int x,const int y) { 37 anc[Find(x)]=Find(y); 38 } 39 }; 40 DisjointSet s; 41 bool vis[V]={0}; 42 int f[V]={0}; 43 void Tarjan(const int x,const int par) { 44 for(int i=e[x];i;i=edge[i].next) { 45 int &y=edge[i].to; 46 if(y!=par) Tarjan(y,x); 47 } 48 for(int i=q[x];i;i=edge[i].next) { 49 int &y=edge[i].to; 50 if(!vis[y]) continue; 51 int lca=s.Find(y); 52 f[x]++,f[y]++,f[lca]-=2; 53 } 54 s.Union(x,par); 55 vis[x]=true; 56 } 57 int cnt[2]={-1}; 58 void DP(const int x,const int par) { 59 for(int i=e[x];i;i=edge[i].next) { 60 int &y=edge[i].to; 61 if(y==par) continue; 62 DP(y,x); 63 f[x]+=f[y]; 64 } 65 if(f[x]<2) cnt[f[x]]++; 66 } 67 int main() { 68 int n=getint(),m=getint(); 69 for(int i=1;i<n;i++) { 70 int u=getint(),v=getint(); 71 add_edge(u,v); 72 add_edge(v,u); 73 } 74 for(int i=1;i<=m;i++) { 75 int u=getint(),v=getint(); 76 add_query(u,v); 77 add_query(v,u); 78 } 79 Tarjan(root,nil); 80 DP(root,nil); 81 printf("%d\n",cnt[0]*m+cnt[1]); 82 return 0; 83 }
时间: 2024-11-05 17:32:29