標籤:net turn std amp int nbsp poj main roo
思路:
考慮加入新邊對原圖的影響:
每加入一條邊,相當於在原圖中構成一個環,因此要使原圖在這個環上斷開,必須刪去這條新邊和環上任意一條樹邊。
統計每一條樹邊出現在多少個環中,計作$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 }
[POJ3417]Network