【2020模拟赛day9】A. 砍苹果树

 

 

 

 

 

 

很经典的一道题目,首先我们考虑每一条附加边x-y 会造成的影响

会使得x-y的简单路径上每条边断开的权值都加1

权值的意义:权值为0,它搭配m条附加边的任意一个都可以

      权值为1,它只能搭配一个附加边

      权值大于1,无论搭配哪个附加边,都无法做到使原图不连通

 

所以我们利用树上差分,处理每条附加边时,先把它加到一个差分数组d中 (这里把边权记在点上,每个点上的值为它和他父亲的连边)

当所有的附加边处理完之后,跑一边dfs累加一下就好了

 

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+5;
int n,m,head[maxn],cnt,dep[maxn];
int f[maxn][20],d[maxn];
struct edge
{
    int to,nxt;
}e[maxn<<1];
void add(int x,int y)
{
    e[++cnt].to=y;
    e[cnt].nxt=head[x];
    head[x]=cnt;
}
void dfs(int u,int fa)
{
    dep[u]=dep[fa]+1;
    f[u][0]=fa;
    for(int i=head[u];i;i=e[i].nxt)
    {
        int to=e[i].to;
        if(to==fa) continue;
        dfs(to,u);
    }
}
void init_lca()
{
    for(int i=1;i<=n;i++)
        for(int j=1;j<=19;j++)
            f[i][j]=f[f[i][j-1]][j-1];
}
int LCA(int x,int y)
{
    if(dep[x]<dep[y]) swap(x,y);
    for(int i=19;i>=0;i--)
        if(dep[f[x][i]]>=dep[y])
            x=f[x][i];
    for(int i=19;i>=0;i--)
        if(f[x][i]!=f[y][i])
            x=f[x][i],y=f[y][i];
    return f[x][0];
}
void calc(int u,int fa)
{
    for(int i=head[u];i;i=e[i].nxt)
    {
        int to=e[i].to;
        if(to==fa) continue;
        dfs(to,u);
        d[u]+=d[to];
    }
}
int main()
{
    freopen("tree.in","r",stdin);
    freopen("tree.out","w",stdout);
    scanf("%d%d",&n,&m);
    int x,y;
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y); add(y,x);
    }
    dfs(1,0);
    init_lca();
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        int lca=LCA(x,y);
        d[x]++; d[y]++;
        d[lca]-=2;
    }
    calc(1,0);
    long long ans=0;
    for(int i=2;i<=n;i++)
    {
        if(!d[i]) ans+=m;
        if(d[i]==1) ans+=1;
    }
    printf("%lld\n",ans);
    return 0;    
} 

 

posted @ 2020-11-28 12:59  andyc_03  阅读(164)  评论(0编辑  收藏  举报