LOJ #6042. 「雅礼集训 2017 Day7」跳蚤王国的宰相

我可以大喊一声这就是个思博题吗?

首先如果你能快速把握题目的意思后,就会发现题目就是让你求出每个点要成为树的重心至少要嫁接多少边

先说一个显然的结论,重心的答案为\(0\)(废话)

然后我们考虑贪心处理,每次肯定要砍断以重心为根的树的大小尽量大的子树

那么至少要砍多少呢,至少\(\frac{1}{2}\)要到吧,然后就是思博的感性理解了——这是每个点要砍的边的上界

假如我们总有一种方案可以使嫁接满足条件(兴许更多,但是这个不会证啊)

那么怎么判断是否达到上界呢,很简单,先取了必要的然后看剩下的有没有超过\(\frac{1}{2}\)即可

这个文字不好表述,大家还是自己看看代码吧

#include<cstdio>
#include<cctype>
#include<algorithm>
#define RI register int
#define CI const int&
#define Tp template <typename T>
using namespace std;
const int N=1000005;
struct edge
{
    int to,nxt;
}e[N<<1]; int n,head[N],x,y,cnt,rt,mx[N],size[N],rch[N],tot,sum,cur,ans[N];
class FileInputOutput
{
    private:
        static const int S=1<<21;
        #define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
        #define pc(ch) (Ftop<S?Fout[Ftop++]=ch:(fwrite(Fout,1,S,stdout),Fout[(Ftop=0)++]=ch))
        char Fin[S],Fout[S],*A,*B; int Ftop,pt[15];
    public:
        Tp inline void read(T& x)
        {
            x=0; char ch; while (!isdigit(ch=tc()));
            while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
        }
        Tp inline void write(T x)
        {
            if (!x) return (void)(pc('0'),pc('\n')); RI ptop=0;
            while (x) pt[++ptop]=x%10,x/=10; while (ptop) pc(pt[ptop--]+48); pc('\n');
        }
        inline void Fend(void)
        {
            fwrite(Fout,1,Ftop,stdout);
        }
        #undef tc
        #undef pc
}F;
inline void addedge(CI x,CI y)
{
    e[++cnt]=(edge){y,head[x]}; head[x]=cnt;
    e[++cnt]=(edge){x,head[y]}; head[y]=cnt;
}
inline int max(CI a,CI b)
{
    return a>b?a:b;
}
inline bool cmp(CI x,CI y)
{
    return size[x]>size[y];
}
#define to e[i].to
inline void getrt(CI now,CI fa=0)
{
    size[now]=1; for (RI i=head[now];i;i=e[i].nxt) if (to!=fa)
    getrt(to,now),size[now]+=size[to],mx[now]=max(mx[now],size[to]);
    if (mx[now]=max(mx[now],n-size[now]),mx[now]<mx[rt]) rt=now;
}
inline void DFS(CI now,CI fa=0)
{
    size[now]=1; for (RI i=head[now];i;i=e[i].nxt)
    if (to!=fa) DFS(to,now),size[now]+=size[to];
}
inline void calc(CI now,CI fa,CI used)
{
    ans[now]=cur+((n-used-size[now]<<1)>n?0:-1);
    for (RI i=head[now];i;i=e[i].nxt) if (to!=fa) calc(to,now,used);
}
int main()
{
    //freopen("B.in","r",stdin); freopen("B.out","w",stdout);
    RI i; for (F.read(n),i=1;i<n;++i) F.read(x),F.read(y),addedge(x,y);
    for (mx[rt]=1e9,getrt(1),i=head[rt];i;i=e[i].nxt) rch[++tot]=to;
    for (DFS(rt),sort(rch+1,rch+tot+1,cmp),i=1;i<=tot;++i)
    if (((sum+=size[rch[i]])<<1)>=n) { cur=i; break; }
    for (i=1;i<=tot;++i) calc(rch[i],rt,sum-max(size[rch[i]],size[rch[cur]]));
    for (i=1;i<=n;++i) F.write(ans[i]); return F.Fend(),0;
}

猜你喜欢

转载自www.cnblogs.com/cjjsb/p/10673266.html