poj3417 Network

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
题意:给你一颗树和一些额外的边,求当你切断一条树边和非树边时,能让这个图不连通的方案数。
我们可以这样考虑,对于一颗树上的每一条边,可以想象它连接了左右两部分,像一个桥(字面意思的桥)连接了左右两个大陆。
如果你想把这个桥毁掉后这两个大陆不连通,你就需要去掉其他的桥。
根据题意我们知道,那些其他的桥肯定是额外的边,那么可以这样判断:
1、如果去掉这个桥后两个大陆不连通,那么有m种方法(随便拆额外边)。
2、如果去掉这个桥后两个大陆只有一个额外桥,那么有一种方法。
3、如果去掉以后有一堆额外桥,因为我们只能拆一个,所以没有办法能拆开。
但是问题来了,怎么判断当前桥的旁的两个大陆有多少额外桥?我们需要用到LCA+树上差分。
对于每一条额外边u->v,如果这条边连了以后,相当于这两个点在树上的最短路径上所有的边,都会受到这条边影响(也就是当它们当做桥时,u->v这条边都会成为额外桥)
因为时间原因,我们不能用DFS求树上最短路径,需要用到LCA。这也用到了树上差分。
对于u、v,我们让差分值dif[u]++,dif[v]++,dif[lca(u,v)]--;
然后令f[i]代表以i为根节点的树上的dif之和,这个值就代表i到i的父亲这条边的额外桥。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#define REP(i,k,n)  for(int i=1;i<=n;i++)
#define in(a) a=read()
#define MAXN 100010
using namespace std;
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar())
        if(ch=='-')
            f=-1;
    for(;isdigit(ch);ch=getchar())
        x=x*10+ch-'0';
    return x*f;
}
int n,m;
int total=0,head[MAXN],nxt[MAXN<<1],to[MAXN<<1];
int vis[MAXN],depth[MAXN],tree[MAXN][30];
int dif[MAXN],f[MAXN],ans;
queue <int> Q;
inline void adl(int a,int b){//邻接表建边
    total++;
    to[total]=b;
    nxt[total]=head[a];
    head[a]=total;
    return ;
}
inline void BFS(){//初始化求lca所需要的数组
    Q.push(1);
    depth[1]=0;
    vis[1]=1;
    while(!Q.empty()){
        int u=Q.front();
        Q.pop();
        REP(i,1,21)  tree[u][i]=tree[tree[u][i-1]][i-1];
        for(int e=head[u];e;e=nxt[e])
            if(!vis[to[e]]){
                vis[to[e]]=1;
                depth[to[e]]=depth[u]+1;
                tree[to[e]][0]=u;
                Q.push(to[e]);
            }
    }
    return ;
}
inline int lca(int u,int v){//求lca
    if(depth[u]<depth[v]) swap(u,v);
    int d=depth[u]-depth[v];
    for(int i=0;(1<<i)<=d;i++)
        if((1<<i)&d)
            u=tree[u][i];
    if(u==v)  return v;
    for(int i=21;i>=0;i--)
        if(tree[u][i]!=tree[v][i]){
            u=tree[u][i];
            v=tree[v][i];
        }
    return tree[u][0];
}
inline void DFS(int u,int fa){//求出f数组
    f[u]=dif[u];
    for(int e=head[u];e;e=nxt[e])
        if(to[e]!=fa){
            DFS(to[e],u);
            f[u]+=f[to[e]];
        }
    return ;
}
int main(){
    in(n);in(m);
    int a,b;
    REP(i,1,n-1)  in(a),in(b),adl(a,b),adl(b,a);
    BFS();
    REP(i,1,m)  in(a),in(b),dif[a]++,dif[b]++,dif[lca(a,b)]-=2;//差分过程
    DFS(1,0); 
    REP(i,1,n){
        if(f[i]==0 && i!=1)  ans+=m;
        if(f[i]==1)  ans+=1;
    }
    cout<<ans;
    return 0;
}

 

 
posted @ 2018-10-07 15:31  Dijkstra·Liu  阅读(254)  评论(0编辑  收藏  举报