并查集解决染色问题

题目传送门
解题思路:
倒着遍历染色区间,首先二分找出区间中第一个没有被染色的点,然后通过并查集枚举并merge所有没有被染色的点,merge操作为将点id连接到find(id)即可,这样每个点只会枚举一次,时间复杂度为O(n)。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
    vector<int>v;
    void dfs(TreeNode* root){
        if(root == NULL)    return;
        dfs(root->left);
        v.emplace_back(root->val);
        dfs(root->right);
    }
    int func(int val,vector<int>& v){
        int n = v.size();
        int l = 0,r = n;
        while(l<r){
            int mid = (l+r)>>1;
            if(v[mid] >= val){
                r = mid;
            }else{
                l = mid+1;
            }
        }
        return l;
    }
    int fa[100005] = {0};
    int find(int val){
        if(fa[val] != val){
            fa[val] = find(fa[val]);
        }
        return fa[val];
    }
public:
    int getNumber(TreeNode* root, vector<vector<int>>& ops) {
        v.reserve(100005);
        dfs(root);
        int n = ops.size();
        v.emplace_back(INT_MAX);
        int m = v.size();
        for(int i = 0;i<m;i++)  fa[i] = i;
        int ret = 0;
        for(int i = n-1;i>=0;i--){
            int t = ops[i][0],l = ops[i][1],r = ops[i][2];
            //二分得到v数组中下标大于等于l的位置
            int pos = func(l,v);
            int pa = find(pos);
            while(v[pa] <= r){
                fa[pa] = find(pa+1);
                pa = fa[pa];
                if(t == 1)  ret++;
            }
        }
        return ret;
    }
};

染色进阶版

题目链接
这里通过并查集,可以思考一下怎么用。

答案:从大往小合并链,这个算法本质是快速合并链。实际上如果不用这种方法也是可以的,只是写起来可能没那么简介,每次考虑把点的左右两个点(如果访问过)合并在一起,并重新计算新的集合的大小。
使用这种方法,那么就只用考虑右边即可。

你可能感兴趣的:(算法,算法设计与分析,c++)