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;
    }
    
  • 相关阅读:
    zookeeper使用场景
    zookeeper安装配置
    hadoop 远程调试
    deep learning笔记
    Sentiment Analysis(1)-Dependency Tree-based Sentiment Classification using CRFs with Hidden Variables
    PRML阅读笔记 introduction
    Python 学习笔记(2)
    python nltk 学习笔记(5) Learning to Classify Text
    python nltk 学习笔记(4) Writing Structured Programs
    python nltk 学习笔记(3) processing raw text
  • 原文地址:https://www.cnblogs.com/pealfrog/p/15478549.html
Copyright © 2011-2022 走看看