树形dp记录路径 CF1779F Xorcerer’s Stones

CF1779F Xorcerer’s Stones
树形dp记录路径
首先我们分析一下操作。
对于奇树,进行一次操作后,其异或和不变;对于偶树,进行一次操作后,其异或和为0。
如果我们能让所有点异或和为0,只要在根节点再进行一次操作,就可以得到一种合法操作方案,考虑树形dp出是否存在一种方案, d p u , j dp_{u,j} dpu,j表示以 u u u为根节点的子树内,是否存在异或和为 j j j的操作方案。合并很简单,但是对于 s z u sz_u szu为偶数时,不论其子树内操作如何,都可以进行一次操作,使得 d p u , 0 = 1 dp_{u,0}=1 dpu,0=1
对于方案的记录,我们开一个 p r e v , j x o r k = j pre_{v,jxork}=j prev,jxork=j,表示 d p u , j x o r k = 1 dp_{u,jxork}=1 dpu,jxork=1这种方案是在儿子异或和为 k k k的情况下,根节点异或和为 j j j的情况下合并转移而来的,因为dp时 u u u的儿子由前往后遍历转移,那么输出路径时就应该由后往前遍历

#include 
#define ll long long
struct node{
    int x,y;
};
void solve(){
    int n;
    std::cin>>n;
    std::vector<int> a(n+1);
    for (int i=1;i<=n;i++){
        std::cin>>a[i];
    }

    std::vector<std::vector<int>> e(n+1);
    for (int i=2;i<=n;i++){
        int x;
        std::cin>>x;
        e[x].push_back(i);
        e[i].push_back(x);
    }

    std::vector<int> sz(n+1);
    std::vector<std::vector<int>> dp(n+1,std::vector<int>(32)),pre(n+1,std::vector<int>(32));
    std::function<void(int,int)> dfs=[&](int u,int fa){
        sz[u]=1;
        dp[u][a[u]]=1;
        for (auto v:e[u]){
            if (v==fa) continue;
            dfs(v,u);
            std::vector<int> use(32);
            std::swap(dp[u],use);
            for (int j=0;j<32;j++){
                if (!use[j]) continue;
                for (int k=0;k<32;k++){
                    if (!dp[v][k]) continue;
                    dp[u][j^k]=1;
                    pre[v][j^k]=j;
                }
            }
            sz[u]+=sz[v];
        }
        if (!(sz[u]&1)){
            dp[u][0]=1;
        }
    };
    dfs(1,-1);

    std::vector<int> ans;
    std::function<void(int,int,int)> prin=[&](int u,int fa,int sum){
        if (!(sz[u]&1)&&!sum){
            ans.push_back(u);
        }
        reverse(e[u].begin(),e[u].end());
        for (auto v:e[u]){
            if (v==fa) continue;
            prin(v,u,sum^pre[v][sum]);
            sum=pre[v][sum];
        }
    };
    if (dp[1][0]){
        prin(1,-1,0);
        std::cout<<ans.size()+1<<"\n";
        for (auto i:ans){
            std::cout<<i<<" ";
        }
        std::cout<<"1";
    }else{
        std::cout<<"-1";
    }
}
int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);

    solve();
    return 0;
}

你可能感兴趣的:(dp,树形dp,codeforces,算法)