P4186 【[USACO18JAN]Cow at Large G】

思路是覆盖子树,我们发现,农民想截住牛的最优策略是不断向上来尽可能地覆盖更大的子树

我们想要尽早地覆盖一个子树,一个显然的贪心是在这个子树中选取深度最小的一个放农民

如果我们在一个点放置了农民,那么其他点也会被覆盖,所有这个农民能够覆盖的叶子都不需要再放农民了

抽象出来,对于每个叶节点,都有一个深度,我们把叶节点按深度排序,然后每次选取深度最浅的点打标记,然后枚举每个点,把这个点能覆盖的点全部删去

那么我们怎样支持这样一种操作呢,我们可以用一个$set$,每次取出$s.begin$,考虑它是否能够覆盖点$x$,能够覆盖的前提是$d[begin]-d[lca]<=d[lca]$,即农民比奶牛先或同时走到$lca$

复杂度我不会证,如果有大佬看到可以帮忙证一下

#include<iostream>
#include<cstdio>
#include<cstring>
#include<set>
using namespace std;
const int maxn=1e5+10,lg=18;
struct edge{
    int next,to;
}e[maxn*2];
struct node{
    int d,id;
};
int n,k,head[maxn],cnt,ans,d[maxn],deg[maxn],sk[maxn][20];
set<node>s;
bool operator <(const node &x,const node &y)
{
    return x.d==y.d?x.id<y.id:x.d<y.d;
}
void add(int x,int y)
{
    e[++cnt].next=head[x];
    e[cnt].to=y;
    head[x]=cnt;
}
void make(int x,int pre)
{
    sk[x][0]=pre,d[x]=d[pre]+1;
    if(deg[x]==1)
        s.insert((node){d[x],x});
    for(int v,i=head[x];i;i=e[i].next)
        if((v=e[i].to)!=pre)
            make(v,x);
}
void equals(int &x,int h)
{
    for(int i=0;h;i++)
    {
        if(h&1)
            x=sk[x][i];
        h>>=1;
    }
}
int lca(int x,int y)
{
    if(d[x]<d[y])
        swap(x,y);
    equals(x,d[x]-d[y]);
    if(x==y)
        return x;
    for(int i=lg;i>=0;i--)
        if(sk[x][i]!=sk[y][i])
            x=sk[x][i],y=sk[y][i];
    return sk[x][0];
}
int main()
{
    scanf("%d%d",&n,&k);
    for(int x,y,i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y),add(y,x);
        deg[x]++,deg[y]++;
    }
    if(deg[k]==1)
    {
        printf("1
");
        return 0;
    }
    d[0]=-1;
    make(k,0);
    for(int i=1;i<=lg;i++)
        for(int j=1;j<=n;j++)
            sk[j][i]=sk[sk[j][i-1]][i-1];
    while(!s.empty())
    {
        node u=*s.begin();
        ans++;
        s.erase(s.begin());
        for(set<node>::iterator it=s.begin();it!=s.end();)
        {
            node tmp=*it;
            it++;
            if(d[u.id]<=2*d[lca(u.id,tmp.id)])
                s.erase(tmp);
        }
    }
    printf("%d
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/ivanovcraft/p/9793221.html