239. 奇偶游戏 带权并查集 种类(扩展域)并查集 两种解法

题目

239. 奇偶游戏 带权并查集 种类(扩展域)并查集 两种解法_第1张图片

题解思路

复习了下 (几个月没碰又忘了)
带权并查集是用来判断某些东西的一种相互关系。
边权代表与根节点的权值进而判断与其他节点的关系。
带权并查集一般都需要进行区间的处理 变成 左开右闭 ()
权值转移

            w[fx] = ( book + w[y] - w[x] + 2 ) % 2 ;
            a[fx] = fy ;

判定的话只需要用小的减大的即可。

种类(扩展域)并查集
239. 奇偶游戏 带权并查集 种类(扩展域)并查集 两种解法_第2张图片
将偶数关系视为同类
和就之前帮派那题差不多了。

AC代码
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

const  int  INF =  0x3f3f3f3f;

unordered_map <int , int  > q ;
int a[100100]  , w[100100] ;

int find2(int x)
{
	if (x != a[x])
	{
		int t = a[x];   //暂存父节点
		a[x] = find2(a[x]); //寻找根节点并且合并
		w[x] = ( w[t] + w[x] )%2 ;   //找到根节点后 不断将根节点前的点的权值累加并更新
	}    //(递归思想) 最后x和根节点相连
	return a[x]; //并且累加上了之前(从X到根节点)的权值
}


int main ()
{
    ios::sync_with_stdio(false);
    int n ,m , flag = 0  ;
    cin>>n>>m;
    n = 1 ;
    for (int i = 1 ; i <= 2*m + 1  ; i++ )
        a[i] = i;
    for (int i = 1 ; i <= m ; i++ )
    {
        string p = "";
        int t1 ,t2 , book = -1 ;
        cin >> t1 >> t2 >> p;
        if ( flag )
            continue;
        if (t1 > t2 )
            swap(t1,t2) ;
        t1-- ;
        if ( q.count(t1) == 0 )
        {
            q[t1] = n;
            n++;
        }
        if ( q.count(t2) == 0 )
        {
            q[t2] = n ;
            n++;
        }
        if ( p == "even")
            book = 0 ;
        else
            book = 1 ;
        int fx = find2(q[t1]) ;
        int fy = find2(q[t2]) ;
        int x = q[t1] ;
        int y = q[t2] ;
        if ( fx ==  fy )
        {
            if ( book != (w[x] - w[y] + 2 )%2 )
            {
                flag = i-1;
            }
        }else
        {
            w[fx] = ( book + w[y] - w[x] + 2 ) % 2 ;
            a[fx] = fy ;
        }
        if ( i == m && flag == 0 )
            flag = m;
    }
    cout<<flag<<"\n";
    return 0 ;
}

你可能感兴趣的:(巧妙的数据结构,算法)