zoukankan      html  css  js  c++  java
  • Codeforces1508D

    Codeforces1508D - Tree Calendar

    题目大意:

    有一棵已知的有根树和一个未知的( ext{dfs})序,且做了若干次操作,每次操作是

    对于所有的((u,fa_u)and label_{fa_u}<label_{u}),找到最小的二元组((label_{fa_u},lable_u)),交换二元组的(label)

    给定最终的序列,求复原一个( ext{dfs})序并且给出操作次数,或者确定不存在这样的( ext{dfs})

    [ ]

    模拟这样的过程,容易发现:

    1号节点沿着最小( ext{dfs})序路径走下去,直到叶子,同时将路径上的点推上来,一共推了(dep_{leaf})

    2号节点沿着最小( ext{dfs})序路径走下去,直到叶子,同时将路径上的点推上来,一共推了(dep_{leaf'})

    ....

    考虑每个节点都已经推到最底下的情况,则最终所有的节点有两种情况

    1.是推下来的节点,则其(label)恰好为原树上出栈序列的标号

    2.剩下的点构成一个新的连通块,按照新的( ext{dfs})序的顺序标号

    那么考虑找到当前最小的二元组((label_{fa_u},label_u)),就知道当前正在推的是哪个元素

    考虑先复原这个元素被推下来的过程,复原的过程中注意判定是否当前的元组合法

    然后容易通过当前的(label)确定一开始的( ext{dfs})

    具体的,设(s_u)(u)子树中最小的(label),按照(s_u)递增的顺序遍历每个儿子得到的( ext{dfs})才可能是合法的( ext{dfs})

    原理比较显然,已经被推的叶子按照( ext{stack})序遍历,剩下的按照原先的( ext{dfs})序遍历,最终取( ext{min})然后遍历即合法

    然后按照上面的过程,对于得到的( ext{dfs})序判定是否合法即可

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    typedef unsigned long long ull;
    typedef double db;
    typedef pair <int,int> Pii;
    #define reg register
    #define mp make_pair
    #define pb push_back
    #define Mod1(x) ((x>=P)&&(x-=P))
    #define Mod2(x) ((x<0)&&(x+=P))
    #define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
    #define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
    template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
    template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }
    
    char IO;
    template <class T=int> T rd(){
    	T s=0; int f=0;
    	while(!isdigit(IO=getchar())) f|=IO=='-';
    	do s=(s<<1)+(s<<3)+(IO^'0');
    	while(isdigit(IO=getchar()));
    	return f?-s:s;
    }
    
    const int N=3e5+10;
    
    int n;
    int A[N],F[N];
    vector <int> G[N];
    ll ans;
    int X[N],Y[N],Z[N],C1,C2,C3,D[N];
    // X 原树 dfs 序
    // y 原树 stack 序
    // z 删去已经推完的点之后,剩下的点的 dfs 序
    
    int I[N],J[N];
    void dfs1(int u){
    	I[u]=A[u];
    	for(int v:G[u]) D[v]=D[u]+1,dfs1(v),cmin(I[u],I[v]);
    }
    void dfs2(int u){
    	J[X[u]=++C1]=u;
    	sort(G[u].begin(),G[u].end(),[&](int x,int y){ return I[x]<I[y]; });
    	for(int v:G[u]) dfs2(v);
    	Y[u]=++C2;
    }
    int vis[N];
    void dfs3(int u){
    	if(vis[u]) return;
    	Z[u]=++C3;
    	for(int v:G[u]) dfs3(v);
    }
    
    int main(){
    	n=rd();
    	rep(i,1,n) A[i]=rd();
    	int p=n+1; A[n+1]=n+1;
    	rep(i,2,n) {
    		int u=rd(),v=rd();
    		G[u].pb(v),F[v]=u;
    		if(A[u]<A[v] && A[p]>A[u]) p=u;
    	}
    	int f=1;
    	if(p<=n) while(F[p]) {
    		int f=F[p];
    		// illgal swap
    		if(A[f]<A[p]) return puts("NO"),0;
    		swap(A[p],A[F[p]]);
    		
    		// not optimal swap
    		if(F[f] && A[F[f]]<A[f]) return puts("NO"),0;
    		for(int v:G[f]) if(A[v]>A[f] && A[v]<A[p]) return puts("NO"),0;
    		p=F[p],ans++;
    	}
    	dfs1(1),dfs2(1);
    	rep(i,1,n) if(A[i]<A[p]) f&=A[i]==Y[i],vis[i]=1,ans+=D[i];
    	dfs3(1);
    	rep(i,1,n) if(A[i]>=A[p]) f&=Z[i]+A[p]-1==A[i];
    	if(!f) puts("NO");
    	else {
    		puts("YES");
    		printf("%lld
    ",ans);
    		rep(i,1,n) printf("%d ",X[i]);
    		puts("");
    	}
    }
    
  • 相关阅读:
    记一道乘法&加法线段树(模版题)
    2021CCPC网络赛(重赛)题解
    Codeforces Round #747 (Div. 2)题解
    F. Mattress Run 题解
    Codeforces Round #744 (Div. 3) G题题解
    AtCoder Beginner Contest 220部分题(G,H)题解
    Educational Codeforces Round 114 (Rated for Div. 2)题解
    Codeforces Global Round 16题解
    Educational Codeforces Round 113 (Rated for Div. 2)题解
    AtCoder Beginner Contest 182 F
  • 原文地址:https://www.cnblogs.com/chasedeath/p/14730104.html
Copyright © 2011-2022 走看看