zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    oracle10g安装问题
    oracle10g卸载问题
    c编译过程
    根文件系统制作
    Handler消息传递机制
    Glide图片加载库的使用
    关于FragmentPageAdapter
    Android中set标签的使用
    overridependingtransition方法
    关于View
  • 原文地址:https://www.cnblogs.com/ivanovcraft/p/9793221.html
Copyright © 2011-2022 走看看