zoukankan      html  css  js  c++  java
  • CF1592C Bakry and Partitioning | 异或

    传送门

    题意

    给定一颗大小为(n)带点权的树, 和一个整数(k)
    询问是否可以删除至多(k-1)条边(至少1条), 将树分成至多(k)个连通块,使得每个连通块中的点权异或和相同

    题解

    这种题的思路大概就是考虑分成很多连通块时, 是否能用较少的联通块等效代替

    容易想到, 如果划分成(m)个异或和相同的联通块,当(m)为偶数,肯定也能分成两个异或和为0的连通块,
    同理, (m)为奇数, 也能分成3个相同的连通块

    也就是,要么两个, 要么三个, 分类讨论嘛:


    1. 两个的话简单, 肯定将原树和他的一颗子树分开
      枚举子树即可

    2. 三个的话, 也就是说, 我们要将原树的两颗子树分离开
      那么继续讨论, 两颗子树是否相交:
      image

    如果不相交的话, 我们假设三颗子树的异或和分别为: (a, b, c)
    显然:要满足 (a oplus (b oplus c) = b = c)
    因为(b = c)得到 (b oplus c = 0)
    所以(a = b = c)
    统计是否存在即可

    如果相交的话, 显然: (a oplus b = b oplus c = c)
    得到(a = c , b = 0)
    依然统计即可

    因为a一定为根节点, 上面两个不难统计

    #include <iostream>
    #include <cstdio>
    #include <vector>
    using namespace std;
    
    int read(){
        int num=0, flag=1; char c=getchar();
        while(!isdigit(c) && c!='-') c=getchar();
        if(c == '-') c=getchar(), flag=-1;
        while(isdigit(c)) num=num*10+c-'0', c=getchar();
        return num*flag;
    }
    
    const int N = 290005;
    int T, n;
    int A[N], sum[N], a[N], cnt[N], fa[N];
    vector<int> p[N];
    
    int flag;
    int rflag = 0;
    
    void dp(int x){
        sum[x] = a[x];
        for(auto nex : p[x]) {
            if(nex == fa[x]) continue;
            fa[nex] = x;
            dp(nex);
            sum[x] ^= sum[nex];
        }
    }
    
    void dfs(int x){
        int res = 0;
        for(auto nex : p[x]){
            if(nex == fa[x]) continue;
            dfs(nex);
            if(cnt[nex]) res++;
            if(cnt[nex] && sum[x]==0) rflag=1; 
        }
        if(res >= 2) rflag = 1;
        if(sum[x] == sum[1] || res) cnt[x]=1; 
    }
    
    int main(){
        T = read();
        while(T--){
            n = read(); int k=read();
            for(int i=1; i<=n; i++) {
                sum[i] = 0;
                cnt[i] = 0;
                p[i].clear();
                a[i] = read();
            }
    
            for(int i=1; i<n; i++){
                int u=read(), v=read();
                p[u].push_back(v);
                p[v].push_back(u);
            }
    
            flag = 0; rflag=0;
            dp(1);	
            for(int i=2; i<=n; i++){
                if((sum[1]^sum[i]) == sum[i]) flag=1;
            }
    
            if(!flag && k>=3){
                dfs(1);
                flag = rflag;
            }
    
            printf(flag?"YES
    ":"NO
    ");
        }
        return 0;
    }
    
    
  • 相关阅读:
    一张图帮你分清scroll、offset、client
    js两种显示日期的方法
    理解js的全局变量和局部变量
    中文输入+英文标点+快速编辑Markdown文本+Sublime+Snippet
    Markdown 使用方法
    get和post的区别
    js对象属性方法大总结(收集)
    bfc (收集的)
    客户端网页编程知识总结
    html学习总结
  • 原文地址:https://www.cnblogs.com/ltdjcoder/p/15541521.html
Copyright © 2011-2022 走看看