• 我逝去的贪心——贪心只能过样例 记录一次考试


    考试T2。。。
    呜呜呜
    考试中:老刘!这个T2怎么这么水啊awa
    然后,写代码的时候,老刘突然走过来,给我来一句:dalao,您AK了啊awa
    我:???
    然后我的T2就搞出来了,还过了大样例。
    然后考完了,我16分。。。
    T2的16分。。。
    您AK了啊
    我算是知道了老刘的毒奶是真的名不虚传啊。。。

     

     嗯。
    一看就是和树的重心有关的东西。

    然后我就写了一个树的重心。
    再算出以它为根的全部的子树的大小.(其实这个要找的是这个子树的重心,不是它的根)
    再把子树全部放进一个优先队列里面 ,每次断边取出最大的子树,断掉上面的一条边。
    到这里,我的贪心还是正确的。
    但是,下一步
    断掉子树中  最大子树  和子树根的边。
    我想当然的以为这就是最大的,压根就没有想一下正确性。
    然后,我就过了那个卡掉了一个贪心的大样例。
    (没卡掉大概是因为我的贪心太sb了吧)
    T2就快乐的拿到了16分。


    正解

    考虑我所说的树的重心。
    发现我每一次都要求的树的重心,其实就是使最大子树最小的一个点
    最大子树最小?
    最大**最小?
    二分答案。
    那么是用什么的单调性呢?、

    我们发现,设最大的子树为M,那么答案就是



    找一下awa,就发现,其实如果我限制每个子树的最大的大小,那么删的边的数量就是在不严格单调递增的。
    所以我们就用每个子树的大小去搞,如果一个子树是要大于我们的限制的话,那么就把它割一下,因为这个其实就是在最接近我设定的答案的地方割的,所以一定是最优的
    直接用dfs暴力找,方法就是上面的方法。
    这个很简单啊。。。
    最后找出来的最大子树肯定是把k次割边的机会全部用完的,所以,就是以k为下界的。
    就AC了

    其实吧,这一题,就是对二分的一个理解。
    有一说一,当看到他的答案与最小的最大子树相关的时候,就应该想到二分了。
    但我只想到了树的重心。
    唉,二分还是不够熟悉啊。

    CODE

    #include<bits/stdc++.h>
    #define ll long long
    #define mp(a,b) make_pair(a,b)
    using namespace std;
    struct edge
    {
        int next,to;
    }e[1000001];
    int n,m,k;
    int head[1000001],tot,size[1000001],maxx=INT_MAX,maxxid,size2[1000001],father[1000001],ru[1000001],size3[1000001];int color[100001],cnt,p[1000001];
    void init(int i,int j)
    {
        e[++tot].next=head[i];
        e[tot].to=j;
        head[i]=tot;
    }
    int getf(int x)
    {
        if(father[x]==x)return x;
        else return father[x]=getf(father[x]);
    }
    inline ll read()
    {
        char c=getchar();ll a=0,b=1;
        for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
        for(;c>='0'&&c<='9';c=getchar())a=a*10+c-48;
        return a*b;
    }
    //void Find_first(int x,int fa)//O(n) 我逝去的贪心 
    //{
    //    int maxSUb=0;
    //    size[x]=1;
    //    for(int i=head[x];i!=0;i=e[i].next)
    //    {
    //        int u=e[i].to;
    //        if(u==fa)continue;
    //        Find_first(u,x);
    //        size[x]+=size[u];
    //        maxSUb=max(size[u],maxSUb);
    //    }
    //    maxSUb=max(maxSUb,n-size[x]);
    //    if(maxSUb<maxx)
    //    {
    //        maxx=maxSUb;
    //        maxxid=x;
    //    }
    //}
    //void Find_size_second(int x,int fa)//O(n)
    //{
    //    size2[x]=1;
    //    for(int i=head[x];i!=0;i=e[i].next) 
    //    {
    //        int u=e[i].to;
    //        if(u==fa)continue;
    //        Find_size_second(u,x);
    //        size2[x]+=size2[u];
    //        father[u]=x;
    //    }
    //}
    void cheak(int x,int fa,int val)
    {
        int sum=1;
        for(int i=head[x];i!=0;i=e[i].next)
        {
            int u=e[i].to;
            if(u==fa)continue;
            cheak(u,x,val);
            sum+=size[u];
        }
        if(sum>val)
        {
            int tmp=0;
            for(int i=head[x];i!=0;i=e[i].next)
            {
                int u=e[i].to;
                if(u==fa)continue;
                p[++tmp]=size[u];
            }
            sort(p+1,p+1+tmp);
            for(int i=tmp;i>0;i--)
            {
                sum-=p[i];
                cnt++;
                if(sum<=val)break;
            } 
        }
        size[x]=sum;
    }
    int main()
    {
        freopen("penalty.in","r",stdin);
        freopen("penalty.out","w",stdout);
        n=read();k=read();
        for(int i=1;i<n;i++)
        {
            int x=read(),y=read();
            init(x,y);init(y,x);ru[x]++;ru[y]++;
        }
        int root;
        for(int i=1;i<=n;i++)
        {
            if(ru[i]==1)
            {
                root=i;
                break;
            }
        }
        int l=1,r=n,Max=0;
        while(l<r-1)
        {
            int mid=l+r>>1;
            memset(size,0,sizeof(size));
            cnt=0;
    //        cout<<mid<<endl;
            cheak(root,0,mid);
            if(cnt>k)l=mid;
            else r=mid;
        }
        cheak(root,0,l);
        if(cnt<=k)
        Max=l;
        else
        Max=r;
        cout<<1ll*Max*(k+1)-1ll*n<<endl;;
    //    for(int i=1;i<=n;i++)father[i]=i;   // 纪念我逝去的贪心。。。 
    //    Find_first(root,-1);
    //    cout<<maxxid<<endl;    
    //    Find_size_second(maxxid,-1);
    //    priority_queue<pair<int,int> > q;
    //    for(int i=1;i<=n;i++)q.push(mp(size2[i],i));//O(nlogn)
    //    for(int i=1;i<=k;i++)//O(k*n*log n) 我没了。。。  我wa了。。。 
    //    {
    //        pair<int,int> x=q.top();
    //        q.pop();
    //        int si=x.first;
    //        int now=x.second;
    //        int Ma=0,id=0;
    //        for(int i=head[now];i!=0;i=e[i].next)
    //        {
    //            int u=e[i].to;
    //            if(size2[u]>size2[now]||size[u]==size[maxxid]||father[u]!=now)continue;
    //            if(Ma<=size2[u])Ma=size2[u],id=u;
    //        }
    ////        cout<<now<<' '<<id<<"            This is the path which I delide"<<endl;
    //        size2[now]-=size2[id];
    //        father[id]=id;
    //        q.push(mp(size2[now],now));
    //    }
    //    int maxxx=0,ans=0;
    //    for(int i=1;i<=n;i++)
    //    {
    //        maxxx=max(maxxx,size2[i]);
    //    }
    //    for(int i=1;i<=n;i++)//O(nlogn)
    //    {
    //        if(color[getf(i)]==false)
    //        {
    //            color[getf(i)]=true;
    //            ans+=abs(size2[getf(i)]-maxxx);
    //        }
    //    }
    //    cout<<ans<<endl;
        return 0;
    }
  • 相关阅读:
    检查IP地址是否有效(delphi)
    Oracle 常用操作
    DBGrid中顯示行號的終極解決方案(Delphi篇)
    从零开始学Java 第24章 网络聊天室
    JavaScript的循环结构和经典题目
    html5/css3布局(一)
    html常用的基本标签
    HTML5——css基础语法
    JavaScript函数使用和DOM节点
    C语言Ⅰ|博客作业07
  • 原文地址:https://www.cnblogs.com/HLZZPawa/p/12937802.html
Copyright © 2020-2023  润新知