我逝去的贪心——贪心只能过样例

考试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;
}

猜你喜欢

转载自www.cnblogs.com/HLZZPawa/p/12937802.html