HDU 4912 Paths on the tree

点点圈 提交于 2020-03-06 13:59:12

题意

树上有一堆路径,问最多选择多少条路径使得每个点最多被一条路径覆盖


我们先把每条路径 \(u,v\) 的 lca 求出来记为 \(lca_{u,v}\)

然后我们来想一想,对于一个节点来说,选择怎样的一条路径才能让这条路径尽量不影响其他路径

我们就可以选择任意一条 lca位于这个点的路径,因为这样这条路径就不会影响到子树外的那些了,然后我们可以按照 lca 从深到浅的顺序来模拟,这样就一定保证是最优的,因为路径无权,一个点又只能被覆盖一次

// This code writed by chtholly_micromaker(MicroMaker)
#include <bits/stdc++.h>
#define reg register
#define int long long
using namespace std;
const int MaxN=100050;
struct Edge
{
    int nxt,to;
}E[MaxN<<2];
struct Node
{
    int a,b;
    int lca;
}a[MaxN];
template <class t> inline void rd(t &s)
{
    s=0;
    reg char c=getchar();
    while(!isdigit(c))
        c=getchar();
    while(isdigit(c))
        s=(s<<3)+(s<<1)+(c^48),c=getchar();
    return;
}
int hd[MaxN],en,n,m;
int up[MaxN][21],dep[MaxN];
bool vis[MaxN];
inline void adde(int u,int v)
{
    ++en;
    E[en].nxt=hd[u];
    E[en].to=v;
    hd[u]=en;
    return;
}
inline bool cmp(const Node &A,const Node &B)
{
    return dep[A.lca]>dep[B.lca];
}
inline void dfs1(int u,int fa)
{
    up[u][0]=fa;
    for(int i=hd[u];~i;i=E[i].nxt)
    {
        reg int v=E[i].to;
        if(v==fa)
            continue;
        dep[v]=dep[u]+1;
        dfs1(v,u);
    }
    return;
}
inline void Init_lca()
{
    for(int k=1;(1<<k)<=n;++k)
        for(int i=1;i<=n;++i)
            up[i][k]=up[up[i][k-1]][k-1];
    return;
}
inline int lca(int u,int v)
{
    if(dep[u]<dep[v])
        swap(u,v);
    if(dep[u]!=dep[v])
        for(int k=20;k>=0;--k)
            if(dep[up[u][k]]>=dep[v])
                u=up[u][k];
    if(u==v)
        return u;
    for(int k=20;k>=0;--k)
        if(up[u][k]!=up[v][k])
            u=up[u][k],v=up[v][k];
    return up[u][0];
}
inline void work()
{
    memset(hd,-1,sizeof hd);en=0;
    memset(vis,false,sizeof vis);
    reg int u,v,ans=0;
    for(int i=1;i<n;++i)
    {
        scanf("%lld %lld",&u,&v);
        adde(u,v);
        adde(v,u);
    }
    dep[1]=1;
    dfs1(1,1);
    Init_lca();
    for(int i=1;i<=m;++i)
    {
        scanf("%lld %lld",&a[i].a,&a[i].b);
        a[i].lca=lca(a[i].a,a[i].b);
//      printf("lca:  %d , %d  =  %d\n",a[i].a,a[i].b,a[i].lca);
    }
    sort(a+1,a+m+1,cmp);
    for(int i=1;i<=m;++i)
    {
        if(vis[a[i].lca])
            continue;
        reg bool flg=true;
        for(int j=a[i].a;j!=a[i].lca;j=up[j][0])
            if(vis[j])
            {
                flg=false;
                break;
            }
        if(!flg)
            continue;
        flg=true;
        for(int j=a[i].b;j!=a[i].lca;j=up[j][0])
            if(vis[j])
            {
                flg=false;
                break;
            }
        if(!flg)
            continue;
        ++ans;
        vis[a[i].lca]=true;
        for(int j=a[i].a;j!=a[i].lca;j=up[j][0])
            vis[j]=true;
        for(int j=a[i].b;j!=a[i].lca;j=up[j][0])
            vis[j]=true;
    }
    printf("%lld\n",ans);
    return;
}
signed main(void)
{
    while(~scanf("%lld %lld",&n,&m))
        work();
    return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!