C. Bakry and Partitioning 题解(思维+两次dfs)

题目链接

题目思路

这个题目的思路还是没有那么的难

首先如果要分成偶数个块,那么这个树的总异或和一定要为0,并且如果总异或和为0,那么必定可以分为两个联

通块,如果分为奇数个的话,那么就看是否可以分为3个即可,就是先删除一个深度最大的联通块的异或和为总异

或和,然后再dfs判断是否还有另外一个,没想到居然就是两次dfs的事情就行了,主要是没想到先删除

代码

#include<bits/stdc++.h>
#define pii pair<int,int>
#define fi first
#define se second
#define debug cout<<"I AM HERE"<<endl;
using namespace std;
typedef long long ll;
const int maxn=1e5+5,inf=(1ll<<31)-1,mod=1e9+7;
const double eps=1e-6;
int n,k;
vector<int> g[maxn];
int dp[maxn];
int a[maxn];
int dep[maxn];
bool vis[maxn];
void dfs(int u,int fa){
    dp[u]=a[u];
    dep[u]=dep[fa]+1;
    for(auto x:g[u]){
        if(x==fa) continue;
        if(vis[x]) continue;
        dfs(x,u);
        dp[u]^=dp[x];
    }
}
signed main(){
    int _;scanf("%d",&_);
    while(_--){
        scanf("%d%d",&n,&k);
        int sum=0;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            sum^=a[i];
            dep[i]=0;
            g[i].clear();
        }
        for(int i=1,u,v;i<=n-1;i++){
            scanf("%d%d",&u,&v);
            g[u].push_back(v);
            g[v].push_back(u);
        }
        dfs(1,1);
        bool flag=0;
        int ma=-1,id=-1;
        for(int i=2;i<=n;i++){
            if(dp[i]==sum&&dep[i]>ma){
                id=i;
                ma=dep[i];
            }
        }
        if(dp[1]==0){
            flag=1;
        }else{
            if(id!=-1&&k>=3){
                for(int i=1;i<=n;i++){
                    dp[i]=0;
                }
                vis[id]=1;
                dfs(1,1);
                for(int i=2;i<=n;i++){
                    if(dp[i]==sum){
                        flag=1;
                        break;
                    }
                    if(i==n){
                        flag=0;
                    }
                }
                vis[id]=0;
            }
        }
        printf(flag?"YES
":"NO
");
    }
    return 0;
}


不摆烂了,写题
原文地址:https://www.cnblogs.com/hunxuewangzi/p/15366707.html