P3806 题解

看到现有的一篇 DSU on tree 的题解复杂度假了,于是我来再写一篇。

首先重新梳理思路,维护每棵子树内深度为某个值的节点是否存在。

维护这个东西可以直接 DSU on tree 也就是把小的子树内的信息加入大的子树。

然后加入点是判断是否能和已经存在的点构成长度为 \(K\) 的路径。

举个例子,对于经过点 \(rt\) 的从 \(x\)\(y\) 的路径,长度是 \(dep_x - dep_{rt} + dep_y - dep_{rt}\)

令上式值为 \(K\) 再移项就可以知道新加入的点需要满足如何的限制才可以做贡献。

最后注意一个点,我们不能暴力清空数组,正确做法是把这个桶用哈希维护,然后直接 \(O(1)\) 清空哈希表。

另外说一个特殊的地方:这份代码为了省事将加点和贡献放在了一起,如果计算方案数就会计重,如果想避免就需要对于每个子树中的所有节点先计算贡献再加入桶

最后上代码:

#include<bits/stdc++.h>
#include<bits/extc++.h>
using namespace std;
const int maxn = 1e4+114;
int depth[maxn],n,sz[maxn],big[maxn],L[maxn],R[maxn],Node[maxn],tot;
__gnu_pbds::gp_hash_table<int,int> cnt;
vector< pair<int,int> > edge[maxn];
int K;
bool flag;
inline void add(int u,int rt){
    cnt[depth[u]]=1;
    int v=K+depth[rt]*2-depth[u];
    if(cnt[v]==1) flag=true;
}
inline void dfs1(int u,int fa,int w){
    L[u]=++tot;
    Node[tot]=u;
    R[u]=L[u];
    sz[u]=1;
    depth[u]=depth[fa]+w;
    for(pair<int,int> v:edge[u]){
        if(v.first==fa) continue;
        dfs1(v.first,u,v.second);
        sz[u]+=sz[v.first];
        if(sz[v.first]>sz[big[u]]){
            big[u]=v.first;
        }
        R[u]=max(R[u],R[v.first]);
    }
}
inline void dfs2(int u,int fa,bool keep){
    for(pair<int,int> v:edge[u]){
        if(v.first!=fa&&v.first!=big[u]) dfs2(v.first,u,false);
        if(flag==true){
            return ;
        }
    }
    if(big[u]){
        dfs2(big[u],u,true);
        if(flag==true){
            return ;
        }
    }
    add(u,u);
    for(pair<int,int> v:edge[u]){
        if(v.first!=fa&&v.first!=big[u]){
            for(int i=L[v.first];i<=R[v.first];i++){
                add(Node[i],u);
                if(flag==true){
                    return ;
                }
            } 
        }
    }
    if(keep==false){
        cnt.clear();
    }
}
int m;
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<n;i++){
        int u,v,w;
        cin>>u>>v>>w;
        edge[u].push_back(make_pair(v,w));
        edge[v].push_back(make_pair(u,w));
    }
    dfs1(1,0,1);
    while(m--){
        cin>>K;
        flag=false;
        dfs2(1,0,true);
        cnt.clear();
        cout<<(flag==true?"AYE\n":"NAY\n");
    }
}
posted @ 2024-01-30 23:57  ChiFAN鸭  阅读(7)  评论(0编辑  收藏  举报