题目大意:给出一棵树,再给出m条非树边,先割掉一条树边,再割掉一条非树边,问有几种割法,使图变成两部分。
思路:每一条 非树边会和一部分的树边形成一个环,分三种情况:
对于那些没有形成环的树边来说,割掉这条边,就已经使图分离,然后随便割一条非树边就可以了,所以这样的边每次答案加上m。
对于那些只存在在一个环中的树边来说,割掉这条边,再割一条和他存在于同一个环中的那条非树边,也能合法,所以加一。
对于存在于多个环中的树边,无论怎样,都无法合法。
也就是此时我们将题目转化成了树上的覆盖问题,非树边的两个端点覆盖的树上简单路径就是一个环,我们用树上差分来解决这个问题,先处理出lca,f数组表示每个点和父节点所在的边的覆盖次数。
对于每一条非树边,端点是u,v,则f[ u ]和 f [ v ]加一,而u和v的公共祖先是没有影响的,所以f[ lca (u,v) ]要减去2,抵消这个影响。每个节点除了要加上直接对这个点操作的值,还要加上来自子树是否有覆盖,所以dfs求得子树的大小,此时 f 数组则代表每个点的父边所覆盖的次数。
//#include<bits/stdc++.h> #include<cstdio> #include<algorithm> #include<string.h> #include<queue> #include<iostream> #define CLR(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; int n,m; const int maxn=100010; struct edges{ int to ,Next; }a[maxn<<1]; int head[maxn],tot,fa[maxn][23],deg[maxn]; ll f[maxn]; inline void init(){ CLR(head,-1),tot=0; CLR(f,0); } inline void addv(int u,int v){ a[++tot]={v,head[u]}; head[u]=tot; } inline void bfs(){ queue<int >q; deg[1]=0; fa[1][0]=1; q.push(1); while(!q.empty()){ int tmp=q.front(); q.pop(); for(int i=1;i<21;i++) { fa[tmp][i]= fa[fa[tmp][i-1]][i-1]; } for(int i=head[tmp];i!=-1;i=a[i].Next) { int v=a[i].to; if(v==fa[tmp][0])continue; deg[v]=deg[tmp]+1; fa[v][0]=tmp; q.push(v); } } } inline int lca(int u,int v){ if(deg[u] > deg[v])swap(u,v); int hu=deg[u],hv=deg[v]; int tu=u,tv=v; for(int det=hv-hu,i=0;det;det>>=1,i++) if(det&1) tv=fa[tv][i]; if(tu==tv)return tu; for(int i=20;i>=0;i--){ if(fa[tu][i]==fa[tv][i]) continue; tu=fa[tu][i]; tv=fa[tv][i]; } return fa[tu][0]; } inline void dfs(int u){ for(int i=head[u];i!=-1;i=a[i].Next) { int v=a[i].to; if(v!=fa[u][0]){ dfs(v); f[u]+=f[v]; } } } int main(){ init(); cin>>n>>m; for(int i=1;i<n;i++) { int u,v; scanf("%d%d",&u,&v); addv(u,v); addv(v,u); } bfs(); for(int i=1;i<=m;i++) { int u,v; scanf("%d%d",&u,&v); f[u]++; f[v]++; f[lca(u,v)]-=2; // printf("lca %d\n",lca(u,v)); } dfs(1); ll ans=0; for(int i=2;i<=n;i++) { // cout<<i<<" "<<f[i]<<endl; if(f[i]==0){ ans+=m; }else if(f[i]==1){ ans++; } } cout<<ans<<endl; }
Network
Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 6736 | Accepted: 1916 |
Description
Yixght is a manager of the company called SzqNetwork(SN). Now she‘s very worried because she has just received a bad news which denotes that DxtNetwork(DN), the SN‘s business rival, intents to attack the network of SN. More unfortunately, the original network of SN is so weak that we can just treat it as a tree. Formally, there are N nodes in SN‘s network, N-1 bidirectional channels to connect the nodes, and there always exists a route from any node to another. In order to protect the network from the attack, Yixght builds M new bidirectional channels between some of the nodes.
As the DN‘s best hacker, you can exactly destory two channels, one in the original network and the other among the M new channels. Now your higher-up wants to know how many ways you can divide the network of SN into at least two parts.
Input
The first line of the input file contains two integers: N (1 ≤ N ≤ 100 000), M (1 ≤ M ≤ 100 000) — the number of the nodes and the number of the new channels.
Following N-1 lines represent the channels in the original network of SN, each pair (a,b) denote that there is a channel between node a and node b.
Following M lines represent the new channels in the network, each pair (a,b) denote that a new channel between node a and node b is added to the network of SN.
Output
Output a single integer — the number of ways to divide the network into at least two parts.
Sample Input
4 1 1 2 2 3 1 4 3 4
Sample Output
3
Source
POJ Monthly--2007.10.06, Yang Mu
原文地址:https://www.cnblogs.com/mountaink/p/9985365.html