Codeforces Round #747 (Div. 2) D. The Number of Imposters(扩展域并查集 带权并查集)

简介: Codeforces Round #747 (Div. 2) D. The Number of Imposters(扩展域并查集 带权并查集)

linkkk

题意:

有n个人,m对关系,每对关系u , v表示u说v是s。每个人有两个身份,船员和冒名者,船员的话全部为真话,冒名者的话全部为假话。问最多有多少个冒名者。

思路:

经典并查集(不是

扩展域并查集,x表示这个人是船员,x + n表示这个人是冒名者。

推理一下关系会发现,如果s为船员c r e w m a t e的话,两者的身份是相同的;否则,两者的身份是不同的,正常合并就可以。

用s i z [ i ]维护i在的集合里冒名者的人数。

最后,如果x和x + n在同一个集合里,说明出现了矛盾。

不然就遍历[ 1 , 2 ∗ n ],对于每个集合取是船员和是冒名者的s i z的最大值。

由于在船员跟冒名者的身份都加了一次,所以最后总和要/ 2

代码:

// Problem: D. The Number of Imposters
// Contest: Codeforces - Codeforces Round #747 (Div. 2)
// URL: https://codeforces.com/contest/1594/problem/D
// Memory Limit: 256 MB
// Time Limit: 3000 ms
// 
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;typedef unsigned long long ull;
typedef pair<ll,ll>PLL;typedef pair<int,int>PII;typedef pair<double,double>PDD;
#define I_int ll
inline ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
#define read read()
#define rep(i, a, b) for(int i=(a);i<=(b);++i)
#define dep(i, a, b) for(int i=(a);i>=(b);--i)
ll ksm(ll a,ll b,ll p){ll res=1;while(b){if(b&1)res=res*a%p;a=a*a%p;b>>=1;}return res;}
const int maxn=4e5+7,maxm=1e6+7,mod=1e9+7;
int root[maxn],siz[maxn],n,m;
int Find(int x){
  if(x!=root[x]) root[x]=Find(root[x]);
  return root[x];
}
void Union(int u,int v){
  int fu=Find(u),fv=Find(v);
  if(fu!=fv){
    root[fu]=fv;
    siz[fv]+=siz[fu];
    siz[fu]=0;
  }
}
int main(){
  int _=read;
  while(_--){
    n=read,m=read;
    rep(i,1,2*n){
      root[i]=i;
      if(i<=n) siz[i]=0;
      else siz[i]=1;
    }
    while(m--){
      int u=read,v=read;
      string s;cin>>s;
      if(s[0]=='i'){
        Union(u,v+n);
        //Union(u+n,v);
        Union(v,u+n);
      }
      else{
        Union(u,v);Union(u+n,v+n);
      }
    }
    // rep(i,1,n){
      // cout<<Find(i)<<" "<<siz[Find(i)]<<endl;
    // }
    int ans=0;
    for(int i=1;i<=2*n;i++){
      int fu=Find(i),fv;
      if(i<=n) fv=Find(i+n);
      else fv=Find(i-n);
      if(fu==fv) ans=-1;
      if(i==fu&&ans!=-1) ans=ans+max(siz[fu],siz[fv]);
    }
    if(ans!=-1)
      cout<<ans/2<<endl;
    else cout<<ans<<endl;
  }
  return 0;
}


目录
相关文章
|
PHP
php保留小数点3种方法,number_format,round和sprintf区分
php保留小数点3种方法,number_format,round和sprintf区分
254 0
|
机器学习/深度学习 Windows
Codeforces Round #748 (Div. 3) F - Red-Black Number (记忆化搜索)
Codeforces Round #748 (Div. 3) F - Red-Black Number (记忆化搜索)
101 0
|
算法
Leetcode 313. Super Ugly Number
题目翻译成中文是『超级丑数』,啥叫丑数?丑数就是素因子只有2,3,5的数,7 14 21不是丑数,因为他们都有7这个素数。 这里的超级丑数只是对丑数的一个扩展,超级丑数的素因子不再仅限于2 3 5,而是由题目给定一个素数数组。与朴素丑数算法相比,只是将素因子变了而已,解法还是和朴素丑数一致的。
100 1
|
5月前
|
存储 SQL 算法
LeetCode 题目 65:有效数字(Valid Number)【python】
LeetCode 题目 65:有效数字(Valid Number)【python】
|
6月前
|
存储 算法
【LeetCode力扣】单调栈解决Next Greater Number(下一个更大值)问题
【LeetCode力扣】单调栈解决Next Greater Number(下一个更大值)问题
45 0
|
存储
Leetcode Single Number II (面试题推荐)
给你一个整数数组,每个元素出现了三次,但只有一个元素出现了一次,让你找出这个数,要求线性的时间复杂度,不使用额外空间。
39 0
|
算法
LeetCode 414. Third Maximum Number
给定一个非空数组,返回此数组中第三大的数。如果不存在,则返回数组中最大的数。要求算法时间复杂度必须是O(n)。
95 0
LeetCode 414. Third Maximum Number
|
存储
LeetCode 313. Super Ugly Number
编写一段程序来查找第 n 个超级丑数。 超级丑数是指其所有质因数都是长度为 k 的质数列表 primes 中的正整数。
97 0
LeetCode 313. Super Ugly Number
|
算法
LeetCode 306. Additive Number
累加数是一个字符串,组成它的数字可以形成累加序列。 一个有效的累加序列必须至少包含 3 个数。除了最开始的两个数以外,字符串中的其他数都等于它之前两个数相加的和。 给定一个只包含数字 '0'-'9' 的字符串,编写一个算法来判断给定输入是否是累加数。 说明: 累加序列里的数不会以 0 开头,所以不会出现 1, 2, 03 或者 1, 02, 3 的情况。
123 0
LeetCode 306. Additive Number
|
算法
LeetCode 268. Missing Number
给定一个包含 0, 1, 2, ..., n 中 n 个数的序列,找出 0 .. n 中没有出现在序列中的那个数。
92 0
LeetCode 268. Missing Number