zoukankan      html  css  js  c++  java
  • CF468D Tree 题解

    Codeforces
    Luogu

    P.S.

    看上去好清真啊,看上去好原题啊,看上去好清新啊,洛谷评分也就一个紫,点开难度。
    woc *3100,恐惧了恐惧了,爪巴了爪巴了。
    和 @Krimson 一起胡的一个做法。

    Description.

    有一棵树,无根边带权。
    一个排列的 \(\{p_i\}\) 权值定义为 \(\sum\text{dist}(i,p_i)\)
    求权值最大值,以及取到这个最大值的最小排列。

    Solution.

    首先,最大值显然是 ATcoder 原题,肯定是每条边达到 \(\max\{sz_u,sz_v\}\)
    然后第一问就做完了,证明就考虑取重心,然后反复横跳(AT 肯定是有原题的。

    第二问考虑同样取重心,把树划分成了若干棵子树(重心本身可以当作一棵方便处理
    考虑转化一下,定义一个树的入度表示这个树还没被匹配的点,出度表示这个树需要匹配的点。
    那能匹配的方案肯定满足每个点都可以匹配,也就是其他点的入度大于当前点的出度。
    我们维护 \(d_i\) 表示 其他点的入度减当前点的出度。
    每次匹配相当于对匹配子树和被匹配子树的 \(d_i\) 不变,其他全局减一。
    要求减完后不出现 \(-1\)

    考虑如果出现了一个 \(d_i=0\),那肯定需要直接匹配这两个。
    但是全局同一时间肯定仅可能有两个 \(d_i=0\),且如果有两个肯定其他已经匹配完了。

    然后每次如果有除了当前子树外的 \(d_i=0\),那只能匹配目标。
    否则就贪心匹配全局最小值,这样肯定不会让 \(d_i\) 变成负数。

    至于全局 \(-1\) 直接维护一个 tag 就行了。

    注意特判重心,因为重心可以和自己匹配,不需要满足 \(d_i\ge 0\) 的限制。

    Coding.

    点击查看代码
    //Coded by leapfrog on 2021.10.28 {{{
    //是啊,你就是那只鬼了,所以被你碰到以后,就轮到我变成鬼了
    #include<bits/stdc++.h>
    using namespace std;typedef long long ll;
    template<typename T>inline void read(T &x)
    {
    	x=0;char c=getchar(),f=0;
    	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
    	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
    	f?x=-x:x;
    }
    template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}}
    const int N=100005;set<int>nd[N],id;set<pair<int,int> >dd;int nid=0;
    struct edge{int to,w,nxt;}e[N<<1];int et,head[N],d[N],p[N];
    int n,sz[N],rt,dfn[N],nfd[N],dt,f[N],tag[N];ll rs=0;
    inline void adde(int x,int y,int w) {e[++et]=(edge){y,w,head[x]},head[x]=et;}
    inline void getrt(int x,int fa)
    {
    	sz[x]=1;int mx=0;for(int i=head[x];i;i=e[i].nxt) if(e[i].to!=fa)
    		getrt(e[i].to,x),sz[x]+=sz[e[i].to],mx=max(mx,sz[e[i].to]);
    	mx=max(mx,n-sz[x]);if(mx<=n/2) rt=x;
    }
    inline void dfs0(int x,int fa)
    {
    	dfn[x]=++dt,nfd[dt]=x,sz[x]=1,f[x]=fa;
    	for(int i=head[x];i;i=e[i].nxt) if(e[i].to!=fa)
    		dfs0(e[i].to,x),sz[x]+=sz[e[i].to],rs+=2ll*min(sz[e[i].to],n-sz[e[i].to])*e[i].w;
    }
    int main()
    {
    	read(n);for(int i=1,x,y,w;i<n;i++) read(x,y,w),adde(x,y,w),adde(y,x,w);
    	if(n==1) return puts("0\n1\n"),0;else if(n==2) return printf("%lld\n2 1\n",2ll*e[head[1]].w),0;
    	getrt(1,0),dfs0(rt,0),printf("%lld\n",rs);
    	for(int i=head[rt],x;i;i=e[i].nxt)
    	{
    		++nid,x=e[i].to;for(int l=dfn[x];l<dfn[x]+sz[x];l++) nd[tag[nfd[l]]=nid].insert(nfd[l]);
    		id.insert(*nd[nid].begin()),dd.insert(make_pair(d[nid]=n-2*nd[nid].size(),nid));
    	}
    	nd[tag[rt]=++nid].insert(rt),dd.insert(make_pair(d[nid]=n-2,nid)),id.insert(rt);
    	int tg=0;for(int i=1;i<=n;i++)
    	{
    		int ps=tag[i],tw;dd.erase(make_pair(d[ps],ps));
    		if(dd.begin()->first+tg==0&&dd.begin()->second!=tag[rt]) tw=dd.begin()->second;
    		else if(tag[*id.begin()]==ps&&i!=rt) tw=tag[*++id.begin()];else tw=tag[*id.begin()];
    		int qw=*nd[tw].begin();p[i]=qw,tg--,dd.erase(make_pair(d[tw],tw));
    		id.erase(qw),nd[tw].erase(nd[tw].begin());if(!nd[tw].empty()) id.insert(*nd[tw].begin());
    		dd.insert(make_pair(++d[ps],ps)),dd.insert(make_pair(++d[tw],tw));
    	}
    	for(int i=1;i<=n;i++) printf("%d%c",p[i],i==n?'\n':' ');
    	return 0;
    }
    
  • 相关阅读:
    django orm
    CentOS7.4 安装mongodb
    Django之logging日志
    Python virtualenv虚拟环境
    不能通过IP访问Docker容器里的Django服务器
    docker学习7-Dockerfile制作自己的镜像文件
    docker学习6-docker-compose容器集群编排
    docker学习5-docker安装tomcat环境和部署war包
    docker学习4-docker安装mysql环境
    深度学习和神经网络的区别
  • 原文地址:https://www.cnblogs.com/pealfrog/p/15478549.html
Copyright © 2011-2022 走看看