[CCO 2026] Tree Traversals 题解

[CCO 2026] Tree Traversals

有点诈骗的好题。

观察条件二,发现按深度把点分成若干层,深度小的在排列里必须优先出现,要决定的只有每一层内部的顺序。

然后要发现它的诈骗之处,设所有层的层内部两两之间最大距离的最大值为 \(mx\),我们可以根据询问的 \(k\) 的大小分成三种情况。

1.\(k<mx\),同一层次内部至少会经过一次这个最大距离(即走到这一层的 lca 再往下的距离),所以若 \(k<mx\) 则一定无解,答案为 \(0\)。

2.\(k>mx\),则说明每一个层内都可以乱排,答案就是每一层的全排之积。

3.\(k=mx\),此时需要我们认真考虑内部的排列方案,一般这种情况下要想到 DP了,而且因为层内是合法的,只要层与层之间也合法即可,那我们似乎主要关注的是每一层由谁开头以及由谁结尾。

用数组 \(E_d\) 按 dfn 序存储所有深度为 \(d\) 的点,此时同一层内距离的最大值,就是 \(E_d\) 内部第一个点到最后一个点的距离。

设 \(f_{u,0/1}\),\(f_{u,0}\) 表示当 \(u\) 是第 \(dep_u\) 层的开头节点,前 \(dep_u-1\) 层已经排好的方案数。\(f_{u,1}\) 表示当 \(u\) 是第 \(dep_u\) 层的结尾节点,前 \(dep_u\) 层已经排好的方案数。

答案要求 \(\sum_{v \in E_{md}} f_{v,1}\),考虑 \(f_{u,1}\) 怎么转移得到。当这一层只有一个节点时 \(f_{u,1}=f_{u,0}\)。否则 \(f_{u,1} = \sum_{v \in E_{dep_u} \land v \neq u} f_{v,0} \times (len-2)!\),其中 \(len\) 表示这一层的节点数。

那就只要考虑求出 \(f_{u,0}\) 了,显然,对于所有 \(dis(u,v) \le mx\) 的上一层节点 \(v\),都有 \(f_{u,0} \leftarrow f_{v,1}\)。一个性质就是,距离最近的点是其父亲节点,而在 \(E_{dep_{fa}}\) 内父亲节点的两边 \(dis(u,v)\) 是单增的,所以我们可以二分找出最左边和最右边满足条件的点的位置。

所以流程大概是这样,因为下一层必须要用到上一层所有点的值,必须一层层的更新,所以我们用一个类似 BFS 的方式更新,每到达一个新的层就直接把每个点的 \(f_{u,1}\) 都用这一层的 \(f_{u,0}\) 更新,而 \(f_{u,0}\) 是被上一层的父亲节点给更新过的。然后再去更新下一层的儿子节点。

但是如果直接更新的话复杂度过高了,注意到两个式子都可以前缀和优化,就做完了。

时间复杂度 \(O(n\log n)\)。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define _int __int128
#define ull unsigned long long
#define pii pair<int,int>
#define fst first
#define scd second
#define pq priority_queue
#define mkp make_pair
#define popcount(x) __builtin_popcount(x)
#define endl '\n'
int T,n,m,mx;
const int N = 1e6+10,mod=1e9+7;
int fac[N];
inline void add(int &x,int y){
    x=(x+y>=mod)?x+y-mod:x+y;
}
vector<int>g[N],e[N];
int s[N];
int k,dep[N],cnt[N],dfn[N],tot,md,rdfn[N],id[N],st[N][22];
int Min(int x,int y){
    return (dfn[x]<dfn[y])?x:y;
}
int lca(int x,int y){
    x=dfn[x],y=dfn[y];
    if(x==y)return rdfn[x];
    if(x>y)swap(x,y);
    x++;
    int k=__lg(y-x+1);
    return Min(st[x][k],st[y-(1<<k)+1][k]);
}
void dfs(int x,int f){
    dep[x]=dep[f]+1;md=max(md,dep[x]);
    dfn[x]=++tot;rdfn[tot]=x;st[tot][0]=f;
    e[dep[x]].push_back(x);
    id[x]=e[dep[x]].size()-1;
    for(auto v:g[x]){
        if(v==f)continue;
        dfs(v,x);
    }
}
int dist(int x,int y){
    return dep[x]+dep[y]-2*dep[lca(x,y)];
}
int f[N][2];
bitset<N>vis;
void dp(int u,int fa){
    int d=dep[fa];
    int l=0,r=id[fa],bl=r,br=r;
    if(cnt[d]==1){
        add(f[u][0],f[fa][1]);
        return;
    }
    while(l<=r){
        int mid=(l+r)/2;
        int v=e[d][mid];
        if(dist(v,u)<=mx){
            bl=mid;
            r=mid-1;
        }else{
            l=mid+1;
        }
    }
    l=id[fa],r=e[d].size()-1;
    while(l<=r){
        int mid=(l+r)/2;
        int v=e[d][mid];
        if(dist(v,u)<=mx){
            br=mid;
            l=mid+1;
        }else{
            r=mid-1;
        }
    }
    bl++,br++;
    add(f[u][0],(s[br]-s[bl-1]+mod)%mod);
}
void bfs(){
    vis[1]=1;int lst=0;
    queue<int>q;q.push(1);
    while(!q.empty()){
        int u=q.front();q.pop();
        if(dep[u]!=lst){//一次更新一层的f[u][1]
            lst=dep[u];
            int len=e[lst].size();s[0]=0;
            for(int i=0;i<len;i++){
                int v=e[lst][i];
                s[i+1]=(s[i]+f[v][0])%mod;
            }
            if(len!=1){
                for(int i=0;i<len;i++){
                    int v=e[lst][i];
                    f[v][1]=(s[len]-f[v][0]+mod)%mod*fac[len-2]%mod;
                }
                s[0]=0;
                for(int i=0;i<len;i++){
                    int v=e[lst][i];
                    s[i+1]=(s[i]+f[v][1])%mod;
                }
            }else{
                f[e[lst][0]][1]=f[e[lst][0]][0];
            }
        }
        for(auto v:g[u]){
            if(vis[v])continue;
            dp(v,u);//下一层的f[v][0]
        }
        for(auto v:g[u]){
            if(vis[v])continue;
            q.push(v);
            vis[v]=1;
        }
    }
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>T;
    fac[0]=1;
    for(int i=1;i<=N-10;i++){
        fac[i]=(fac[i-1]*i)%mod;
    }
    while(T--){
        cin>>n>>m;
        for(int i=1;i<n;i++){
            int u,v;
            cin>>u>>v;
            g[u].push_back(v);
            g[v].push_back(u);
        }
        dfs(1,0);
        for(int j=1;(1<<j)<=tot;j++){
            for(int i=1;i+(1<<j)-1<=tot;i++){
                st[i][j]=Min(st[i][j-1],st[i+(1<<j-1)][j-1]);
            }
        }
        for(int i=1;i<=md;i++){
            cnt[i]=e[i].size();
        }
        int res=1;
        for(int i=1;i<=md;i++){
            res=(res*fac[cnt[i]])%mod;
        }
        for(int i=1;i<=md;i++){
            mx=max(mx,dist(e[i][0],e[i].back()));
        }
        f[1][0]=1;
        bfs();
        int ans=0;
        for(auto v:e[md]){
            add(ans,f[v][1]);
        }
        for(int i=1,k;i<=m;i++){
            cin>>k;
            if(k<mx)cout<<0<<" ";
            else if(k>mx)cout<<res<<" ";
            else cout<<ans<<" ";
        }
        cout<<endl;
        mx=0;vis.reset();tot=0;md=0;
        for(int i=1;i<=n;i++){
            g[i].clear();
            e[i].clear();cnt[i]=0;
            f[i][0]=f[i][1]=0;
            s[i]=0;dep[i]=0;
        }
    }
    return 0;
}
posted @ 2026-10-14 08:32  farenara_sayowell  阅读(3)  评论(0)    收藏  举报