ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF1580E Tree Calendar

2022-08-11 16:02:44  阅读:21  来源: 互联网

标签:dfnin CF1580E int void Tree dfs maxn Calendar 节点


前言

被这道题虐暴了……

正文

题目大意:有一棵 \(n\) 个节点,以 \(1\) 为根的树,你求出它的 dfs 序 \((a_1,...,a_n)\),每次操作可以:

  • 选择最小的 \((a_u,a_v)\),满足 \(u\) 与 \(v\) 有有向边相连且 \(a_u<a_v\),并交换 \(a_u,a_v\)

现在知道 \(k\) 次操作以后的 \(a_i\),请求出 \(k\) 和初始的 dfs 序,或判断无解。

数据范围:\(n\leq 3\cdot 10^5\)

高妙的一道思维题。

你需要观察出来一些性质:

性质1:子节点相对大小关系不会改变。

这是最强的性质,这个的证明也很容易。

假设 \(a_u\) 的子节点从小到大排序后为 \((v_1,...,v_k)\),则如果 \(a_u\) 和 \(a_{v_p}\) 交换必然满足 \(a_u>a_{v_{p-1}}\) 且 \(a_u<a_{v_{p+1}}\)。

所以子节点相对大小关系不变,我们可以直接把原树的 dfs 序构造出来。

性质2:如果 \(k\) 存在,则 \(k\) 步后的 dfs 序为原来的 exit 序。

这个也很好证明。

反证法。假设它不选原来的 exit 序而选了别的,肯定会变得更劣。(因为原来 dfs 序就是每步都选最小的)

有了这两个性质以后,就可以考虑怎样判断可行,可行就需要满足:

  • \(1\) 到 \(i-1\) 要是 exit 序。
  • \(i+1\) 到 \(n\) 要按顺序从上到下排列。
  • \(i\) 得跑对位置。

最后 \(k\) 就是所有 \(1\) 到 \(i-1\) 的点的深度之和。

#include <bits/stdc++.h>
#define sz(x) (int)(x.size())
using namespace std;
const int mod=1e9+7,Base=233,inf=0x3f3f3f3f;
const long long INF=0x3f3f3f3f3f3f3f3f;
template<typename T>inline void chmax(T &a, T b){a=max(a,b);}
template<typename T>inline void chmin(T &a, T b){a=min(a,b);}
inline void trans(int &a,int b){a+=b;if(a>mod)a-=mod;}
const int maxn=3e5+5;
int n,a[maxn],dfnin[maxn],dfnout[maxn],fa[maxn],dep[maxn],dfnin_tim=0,dfnout_tim=0;
vector<int> g[maxn];
int vv[maxn],pos[maxn];
void dfs(int u)
{
	dfnin[u]=++dfnin_tim;
	vector<pair<int,int>> tmp;
	for(int i=0;i<sz(g[u]);i++)
	{
		int v=g[u][i];
		fa[v]=u;
		dep[v]=dep[u]+1;
		tmp.push_back(make_pair(a[v],v));
	}
	sort(tmp.begin(),tmp.end());
	for(int i=0;i<sz(tmp);i++)
		dfs(tmp[i].second);
	dfnout[u]=++dfnout_tim;
	vv[dfnout_tim]=u;
}
bool anc(int x,int y)
{
	if(x==y)
		return true;
	if(x==1)
		return false;
	return anc(fa[x],y);
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    cin>>n;
    for(int i=1;i<=n;i++)
    {
    	cin>>a[i];
    	pos[a[i]]=i;
	}
    int u,v;
    for(int i=1;i<n;i++)
    {
    	cin>>u>>v;
    	g[u].push_back(v);
	}
	dfs(1);
	if(a[1]==1)
	{
		for(int i=1;i<=n;i++)
			if(a[i]!=dfnin[i])
			{
				cout<<"NO\n";
				return 0;
			}
		cout<<"YES\n0\n";
		for(int i=1;i<=n;i++)
			cout<<a[i]<<" ";
		cout<<"\n";
		return 0;
	}
	int push_val=a[1]-1,push_pos;
	for(int i=1;i<=n;i++)
		if(a[i]==push_val)
		{
			push_pos=i;
			break;
		}
	for(int i=1;i<=n;i++)
	{
		if(a[i]<push_val&&a[i]!=dfnout[i])
		{
			cout<<"NO\n";
			return 0;
		}
	}
	if(!anc(vv[push_val],pos[push_val]))
	{
		cout<<"NO\n";
		return 0;
	}
	long long res=0;
	while(push_pos!=1)
	{
		res++;
		swap(a[push_pos],a[fa[push_pos]]);
		push_pos=fa[push_pos];
	}
	for(int i=1;i<=n;i++)
	{
		if(a[i]>=push_val&&a[fa[i]]>a[i])
		{
			cout<<"NO\n";
			return 0;
		}
	}
	cout<<"YES\n";
	for(int i=1;i<=n;i++)
		if(a[i]<push_val)
			res+=dep[i];
	cout<<res<<"\n";
	for(int i=1;i<=n;i++)
		cout<<dfnin[i]<<" ";
	cout<<"\n";
    return 0;
}

标签:dfnin,CF1580E,int,void,Tree,dfs,maxn,Calendar,节点
来源: https://www.cnblogs.com/Jerry-Jiang/p/16576261.html

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有