题解:AT_abc397_e [ABC397E] Path Decomposition of a Tree

· · 题解

赛时死因:k=1

首先因为找的是路径,所以对于每个叶子节点,它一定会是某条路径的端点之一。

那么考虑类似拓扑排序,对每个叶子节点,即度数为一的点入队,然后可以想象成将一个点合并到与它相连的点,并记录下到这个点的路径长度。

对于一条完整的路径,想象把它删除,因为它的一端是叶子节点,那么只需将另一端点相连的点度数减一,如果成为新的叶子节点就再入队。

大体思路是这样,然后有以下细节需要在遍历时判断:

代码:

    #include<bits/stdc++.h>
    using namespace std;
    vector<int> g[200005];
    bool f;
    int n,k,d[200005],a[200005],vis[200005];
    queue<int> q;
    int main()
    {
        cin>>n>>k;
        for(int i=1;i<n*k;i++)
        {
            int u,v;
            cin>>u>>v;
            g[u].push_back(v);
            g[v].push_back(u);
            d[u]++,d[v]++;
        }
        if(k==1)
        {
            cout<<"Yes";
            return 0;
        } 
        for(int i=1;i<=n*k;i++)
        {
            a[i]=1;
            if(d[i]==1) 
                q.push(i);
        }
        while(!q.empty())
        {
            int u=q.front();
            q.pop();
            vis[u]=1;
            for(int v:g[u])
            {
                if(vis[v]) 
                    continue;
                if(!a[u])
                {
                    d[v]--;
                    if(d[v]==1) 
                        q.push(v);
                    break;
                }
                d[v]--;
                if(!a[v])
                {
                    cout<<"No";
                    return 0;
                }
                if(a[v]!=1)
                {
                    a[v]+=a[u];
                    if(a[v]!=k)
                    {
                        cout<<"No";
                        return 0;
                    }
                    a[v]=0;
                }
                else 
                    a[v]+=a[u];
                if(a[v]==k) 
                    a[v]=0;
                if(d[v]==1) 
                    q.push(v);
                break;
            }
        }
        cout<<"Yes";
        return 0;
    }