POJ 3417 Network

来源:互联网 发布:死而后已不亦远乎翻译 编辑:程序博客网 时间:2024/06/06 06:39

Network
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 5308 Accepted: 1520
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

每加一条新边u-v树必成环u-lca(u,v)-v-u,给这个环上的所有树边覆盖数加一,加完新边之后,考虑树边的覆盖数:
如果一条树边的覆盖数大于1,那么显然这条树边是牢固的,即删去这条树边再删去任一条新边树都不会断裂;
如果一条树边的覆盖数为1,那么删去这条树边之后,只有再同时删去产生这个覆盖数的那条新边,树才会断裂,所以方案数加一;
如果一条树边的覆盖数为0,那么删去这条树边之后,任意删去一条新边树都会断裂,方案数加m;
那么如何统计一条边的覆盖数?首先给树固定一个方向,不妨选1节点为树根,令dp[i]表示以i为终点(在树中深度较深的点)的边的覆盖数,那么每次加一条新边u-v,只要更新u-lca(u,v)和v-lca(u,v)两条路径上的边即可,这里类似前缀和优化,dp[u]++,dp[v]++,dp[lca(u,v)]-=2,那么在操作完后深搜一遍整棵树在回溯的时候利用树形DP,dp[fa]+=sum(dp[son])即可得到每条边的覆盖数

xxy搬过来给我们考试的一道题,然而这场考试只能让我愈发佩服hkd的搜题解能力

#include<iostream>#include<cstring>#include<cstdio>#define MAXN 111111using namespace std;struct Edge{ int to,next; }e[MAXN*2];int dep[MAXN],fa[MAXN][55],vis[MAXN],head[MAXN],tot,dp[MAXN];void init(){    tot=0;    memset(head,-1,sizeof head );    memset(vis,0,sizeof vis );    memset(dep,0,sizeof dep );    memset(fa,-1,sizeof fa );    memset(dp,0,sizeof dp );}void Add_Edge(int u,int v){    e[++tot].to=v,e[tot].next=head[u],head[u]=tot;}void DFS(int u){    vis[u]=1;    for(int i=head[u];~i;i=e[i].next){        int v=e[i].to;        if(!vis[v]){            fa[v][0]=u,dep[v]=dep[u]+1;            DFS(v);        }    }}void RMQ(int n){    for(int j=1;(1<<j)<=n;++j)        for(int i=1;i<=n;++i)            if(~fa[i][j-1]) fa[i][j]=fa[fa[i][j-1]][j-1];}int LCA(int u,int v){    if(dep[u]<dep[v]) swap(u,v);    int i,j;    for(i=0;(1<<i)<=dep[u];++i);    --i;    for(j=i;j>=0;--j)        if(dep[u]-(1<<j)>=dep[v]) u=fa[u][j];    if(u==v) return u;    for(j=i;j>=0;--j)        if(fa[u][j]!=-1&&fa[u][j]!=fa[v][j]) u=fa[u][j],v=fa[v][j];    return fa[u][0];}void DP(int u){    vis[u]=1;    for(int i=head[u];~i;i=e[i].next){        int v=e[i].to;        if(!vis[v]){            DP(v);            dp[u]+=dp[v];        }    }}int main(){    int n,m,u,v;    while(~scanf("%d%d",&n,&m)){        init();        for(int i=1;i<n;++i) {            scanf("%d%d",&u,&v);            Add_Edge(u,v),Add_Edge(v,u);        }        DFS(1);RMQ(n);        for(int i=1;i<=m;++i){            scanf("%d%d",&u,&v);            ++dp[u],++dp[v],dp[LCA(u,v)]-=2;        }        memset(vis,0,sizeof vis );        DP(1);        int Ans=0;        for(int i=2;i<=n;++i)            if(dp[i]==0) Ans+=m;            else if(dp[i]==1) Ans++;        printf("%d\n",Ans);    }    return 0;}
原创粉丝点击