传送门

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.

题意:

传说中的暗之连锁被人们称为Dark。Dark是人类内心的黑暗的产物,古今中外的勇者们都试图打倒它。经过研究,你发现Dark呈现无向图的结构,图中有N个节点和两类边,一类边被称为主要边,而另一类被称为附加边。Dark有N – 1条主要边,并且Dark的任意两个节点之间都存在一条只由主要边构成的路径。另外,Dark还有M条附加边。 你的任务是把Dark斩为不连通的两部分。一开始Dark的附加边都处于无敌状态,你只能选择一条主要边切断。一旦你切断了一条主要边,Dark就会进入防御模式,主要边会变为无敌的而附加边可以被切断。但是你的能力只能再切断 Dark的一条附加边。现在你想要知道,一共有多少种方案可以击败Dark。注意,就算你第一步切断主要边之后就已经把Dark斩为两截,你也需要切断一条附加边才算击败了Dark。

思路:
最开始的我的想法是判桥,但是给了我们两类边,而且思路好像也不正确。我们要注意到题目上给的N - 1条主要边构成的一棵,然后再给我们 m 条次要边,肯定会与树上的边形成环。

由上面的图我们可以发现:如果一条主要边被覆盖的次数==0,那么我们任意砍断一条次要边都可以。如果一条被覆盖一次,我们只能通过砍断覆盖的那一条次要边使图分成两部分。如果一条边被覆盖2次或2次以上,则不可能通过砍掉这条主要边达成要求

如果给你一条次要边 edge(x,y),我们就需要将 x - LCA(x,y) 和 y - LCA(x,y) 上的所有边加上1,如果暴力加上1,肯定会T掉。树上的一条链我们可以看作是一个线性结构。我们可以通过将 x - root 和 y- root 上所有边 加上1 ,LCA(x,y) - root 上的所有边在减去2 。这样可以达到同样的效果。这个问题我们可以用差分来简单解决。我们用 dp[i] 表示 i 到 i 的父亲结点这条边被覆盖过几次。我们只需要将 dp[ x ] ++,dp[ y ]++ ,dp[ LCA( x , y ) ] - = 2。然后从叶子结点往根上面回溯。dp[ father[ i ] ] += dp[ i ]。

代码:
 

///#include<bits/stdc++.h>
///#include<unordered_map>
///#include<unordered_set>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<set>
#include<stack>
#include<map>
#include<new>
#include<vector>
#define MT(a,b) memset(a,b,sizeof(a));
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double pai=acos(-1.0);
const double E=2.718281828459;
const int mod=1e9+7;
const int INF=1e9;

int n,m;

struct node
{
    int e;
    int p;
} load[200005],edge[200005];
int head[100005],sign;
int rehead[100005];///记录深度的邻接表

void add_edge(int s,int e)
{
    load[++sign]=node{e,head[s]};
    head[s]=sign;
}

void add(int s,int e)
{
    edge[++sign]=node{e,rehead[s]};
    rehead[s]=sign;
}

int depth[100005];
int grand[100005][20],N;
int dp[100005];
vector<int>q[100005];

void dfs(int s,int pre)
{
    for(int i=1; i<=N; i++)
        grand[s][i]=grand[grand[s][i-1]][i-1];
    for(int i=head[s]; i!=-1; i=load[i].p)
    {
        int e=load[i].e;
        if(e!=pre)
        {
            depth[e]=depth[s]+1;
            grand[e][0]=s;
            add(depth[e],e);    ///不能用vector,会T
            dfs(e,s);
        }
    }
}

int get_lca(int a,int b)
{
    if(depth[a]>depth[b])
        swap(a,b);
    for(int i=N; i>=0; i--)
        if(depth[b]>=depth[a]&&depth[grand[b][i]]>=depth[a])
            b=grand[b][i];
    for(int i=N; i>=0; i--)
    {
        if(grand[a][i]!=grand[b][i])
        {
            a=grand[a][i];
            b=grand[b][i];
        }
    }
    return a==b?a:grand[b][0];
}

void init()
{
    N=log2(n);
    sign=0;
    memset(head,-1,sizeof(head));
    memset(rehead,-1,sizeof(rehead));
    memset(depth,0,sizeof(depth));
    memset(dp,0,sizeof(dp));
    memset(grand,0,sizeof(grand));
    depth[0]=-1;
}

int main()
{
    int s,e;
    while(~scanf("%d %d",&n,&m))
    {
        init();
        for(int i=1; i<n; i++)
        {
            scanf("%d %d",&s,&e);
            add_edge(s,e);
            add_edge(e,s);
        }
        sign=0;
        dfs(1,-1);
        for(int i=1;i<=m;i++)
        {
            scanf("%d %d",&s,&e);
            int x=get_lca(s,e);
            dp[s]++;
            dp[e]++;
            dp[x]-=2;
        }
        int sum=0;
        for(int i=n; i>=1; i--)
        {
            for(int j=rehead[i]; j!=-1; j=edge[j].p)
            {
                e=edge[j].e;
                if(dp[e]==0)
                    sum+=m;
                if(dp[e]==1)
                    sum++;
                dp[grand[e][0]]+=dp[e];///向上更新
            }
        }
        printf("%d\n",sum);
    }
    return 0;
}