📜  树上的不相交集联合|套装2

📅  最后修改于: 2021-04-26 05:51:31             🧑  作者: Mango

给定一棵树,子树的代价定义为| S | * AND(S)其中| S |是子树的大小,AND(S)是子树中所有节点索引的按位与,任务是找到可能的子树的最大成本。
先决条件:不交集集合
例子:

Input : Number of nodes = 4
        Edges = (1, 2), (3, 4), (1, 3)
Output : Maximum cost = 4
Explanation : 
Subtree with singe node {4} gives the maximum cost.

Input : Number of nodes = 6
        Edges = (1, 2), (2, 3), (3, 4), (3, 5), (5, 6)
Output : Maximum cost = 8
Explanation : 
Subtree with nodes {5, 6} gives the maximum cost.

方法:策略是修复AND,并找到子树的最大大小,以使所有索引的AND等于给定的AND。假设我们将AND固定为“ A”。在A的二进制表示中,如果第i个位为“ 1”,则所需子树的所有索引(节点)在二进制表示中的第i个位置应为“ 1”。如果第i个位为“ 0”,则索引在第i个位置具有“ 0”或“ 1”。这意味着子树的所有元素都是A的超级掩码。A的所有超级掩码都可以在O(2 ^ k)时间内生成,其中“ k”是A中“ 0”的位数。
现在,可以使用树上的DSU找到具有给定AND“ A”的子树的最大大小。假设“ u”是A的超级掩码,“ p [u]”是u的父代。如果p [u]也是A的超级掩码,那么我们必须通过合并u和p [u]的分量来更新DSU。同时,我们还必须跟踪子树的最大大小。 DSU可以帮助我们做到这一点。如果我们看下面的代码,将会更加清楚。

CPP
// CPP code to find maximum possible cost
#include 
using namespace std;
 
#define N 100010
 
// Edge structure
struct Edge {
    int u, v;
};
 
/* v : Adjacency list representation of Graph
    p : stores parents of nodes */
vector v[N];
int p[N];
 
// Weighted union-find with path compression
struct wunionfind {
    int id[N], sz[N];
    void initial(int n)
    {
        for (int i = 1; i <= n; i++)
            id[i] = i, sz[i] = 1;
    }
 
    int Root(int idx)
    {
        int i = idx;
        while (i != id[i])
            id[i] = id[id[i]], i = id[i];
 
        return i;
    }
 
    void Union(int a, int b)
    {
        int i = Root(a), j = Root(b);
        if (i != j) {
            if (sz[i] >= sz[j]) {
                id[j] = i, sz[i] += sz[j];
                sz[j] = 0;
            }
            else {
                id[i] = j, sz[j] += sz[i];
                sz[i] = 0;
            }
        }
    }
};
 
wunionfind W;
 
// DFS is called to generate parent of
// a node from adjacency list representation
void dfs(int u, int parent)
{
    for (int i = 0; i < v[u].size(); i++) {
        int j = v[u][i];
        if (j != parent) {
            p[j] = u;
            dfs(j, u);
        }
    }
}
 
// Utility function for Union
int UnionUtil(int n)
{
    int ans = 0;
 
    // Fixed 'i' as AND
    for (int i = 1; i <= n; i++) {
        int maxi = 1;
 
        // Generating supermasks of 'i'
        for (int x = i; x <= n; x = (i | (x + 1))) {
            int y = p[x];
 
            // Checking whether p[x] is
            // also a supermask of i.
            if ((y & i) == i) {
                W.Union(x, y);
 
                // Keep track of maximum
                // size of subtree
                maxi = max(maxi, W.sz[W.Root(x)]);
            }
        }
         
        // Storing maximum cost of
        // subtree with a given AND
        ans = max(ans, maxi * i);
         
        // Separating components which are merged
        // during Union operation for next AND value.
        for (int x = i; x <= n; x = (i | (x + 1))) {
            W.sz[x] = 1;
            W.id[x] = x;
        }
    }
         
    return ans;
}
 
// Driver code
int main()
{
    int n, i;
 
    // Number of nodes
    n = 6;
 
    W.initial(n);
 
    Edge e[] = { { 1, 2 }, { 2, 3 }, { 3, 4 },
                 { 3, 5 }, { 5, 6 } };
 
    int q = sizeof(e) / sizeof(e[0]);
 
    // Taking edges as input and put
    // them in adjacency list representation
    for (i = 0; i < q; i++) {
        int x, y;
        x = e[i].u, y = e[i].v;
        v[x].push_back(y);
        v[y].push_back(x);
    }
 
    // Initializing parent vertex of '1' as '1'
    p[1] = 1;
 
    // Call DFS to generate 'p' array
    dfs(1, -1);
 
    int ans = UnionUtil(n);
         
        printf("Maximum Cost = %d\n", ans);
 
    return 0;
}


Python3
# Python3 code to find maximum possible cost
N = 100010
  
# Edge structure
class Edge:
     
    def __init__(self, u, v):
        self.u = u
        self.v = v
  
''' v : Adjacency list representation of Graph
    p : stores parents of nodes '''
 
v=[[] for i in range(N)];
p=[0 for i in range(N)];
  
# Weighted union-find with path compression
class wunionfind:
     
    def __init__(self):
         
        self.id = [0 for i in range(1, N + 1)]
        self.sz = [0 for i in range(1, N + 1)]
     
    def initial(self, n):
         
        for i in range(1, n + 1):
            self.id[i] = i
            self.sz[i] = 1
  
    def Root(self, idx):
     
        i = idx;
         
        while (i != self.id[i]):
            self.id[i] = self.id[self.id[i]]
            i = self.id[i];
  
        return i;
  
    def Union(self, a, b):
     
        i = self.Root(a)
        j = self.Root(b);
         
        if (i != j):
            if (self.sz[i] >= self.sz[j]):
                self.id[j] = i
                self.sz[i] += self.sz[j];
                self.sz[j] = 0;
            else:
                self.id[i] = j
                self.sz[j] += self.sz[i];
                self.sz[i] = 0
  
W = wunionfind()
  
# DFS is called to generate parent of
# a node from adjacency list representation
def dfs(u, parent):
 
    for i in range(0, len(v[u])):
     
        j = v[u][i];
         
        if(j != parent):
            p[j] = u;
            dfs(j, u);
             
# Utility function for Union
def UnionUtil(n):
 
    ans = 0;
  
    # Fixed 'i' as AND
    for i in range(1, n + 1):
     
        maxi = 1;
  
        # Generating supermasks of 'i'
        x = i
        while x<=n:
         
            y = p[x];
  
            # Checking whether p[x] is
            # also a supermask of i.
            if ((y & i) == i):
                W.Union(x, y);
  
                # Keep track of maximum
                # size of subtree
                maxi = max(maxi, W.sz[W.Root(x)]);
             
            x = (i | (x + 1))
            
        # Storing maximum cost of
        # subtree with a given AND
        ans = max(ans, maxi * i);
          
        # Separating components which are merged
        # during Union operation for next AND value.
        x = i
        while x <= n:
            W.sz[x] = 1;
            W.id[x] = x;
            x = (i | (x + 1))
               
    return ans;
  
# Driver code
if __name__=='__main__':
 
    # Number of nodes
    n = 6;
  
    W.initial(n);
  
    e = [ Edge( 1, 2 ), Edge( 2, 3 ), Edge( 3, 4 ),
                 Edge( 3, 5 ), Edge( 5, 6 ) ];
  
    q = len(e)
  
    # Taking edges as input and put
    # them in adjacency list representation
    for i in range(q):
     
        x = e[i].u
        y = e[i].v;
        v[x].append(y);
        v[y].append(x);
      
    # Initializing parent vertex of '1' as '1'
    p[1] = 1;
  
    # Call DFS to generate 'p' array
    dfs(1, -1);
  
    ans = UnionUtil(n);
          
    print("Maximum Cost =", ans)
  
# This code is contributed by rutvik_56


输出:
Maximum Cost = 8

时间复杂度: DSU中的联合需要O(1)时间。生成所有超级掩码需要O(3 ^ k)时间,其中k是最大位数“ 0”。 DFS取O(n)。总时间复杂度为O(3 ^ k + n)。