ICode9

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

CF1580E Tree Calendar

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

标签: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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

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

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

ICode9版权所有