タイトル説明
動物界には、A、B、Cの3種類の動物がいます。これら3種類の動物の食物連鎖は、興味深いリングを形成しています。
AがBを食べ、BがCを食べ、CがAを食べます。
現在、1からNまでの番号が付けられたN匹の動物がいます。
各動物はA、B、Cのいずれかですが、どちらであるかはわかりません。
一部の人々は、これらのNの動物によって形成された食物連鎖の関係を2つの方法で説明します。
最初のステートメントは「1 XY」です。これは、XとYが同じ種類であることを意味します。
2番目のステートメントは「2 XY」です。これは、XがYを食べることを意味します。
この人は、上記の2つのステートメントを使用して、N匹の動物にK文を次々と言います。
文が次の3つの項目のいずれかを満たす場合、その文は偽であり、そうでない場合は真です。
1)現在の単語は、嘘である以前の真の単語と競合しています;
2)現在の単語XまたはYは、嘘であるNよりも大きいです;
3)現在の単語は、Xが嘘であるXを食べることを意味します。
あなたの仕事は、与えられたNとKの文に基づいて嘘の総数を出力することです。
入力形式
最初の行は、スペースで区切られた2つの整数NとKです。
次の各K行には、2つの数値の間のスペースで区切られた3つの正の整数D、X、Yが含まれています。Dは引数のタイプを表します。
D = 1の場合、XとYが同じ種類であることを意味します。
D = 2の場合、XがYを食べることを意味します。
出力形式に
は、嘘の数を表す整数が1つだけあります。
データ範囲
1≤N≤50000、
0≤K≤100000
入力例:
100 7
1 101 1
2 1 2
2 2 3
2 3 3
1 1 3
2 3 1
1 5 5
出力例:
3
トピック分析
まず、入力を確認し、k行を求めて、2匹の動物xとyの関係を毎回説明します。
第二に、どのように文が嘘であるかを確認してください
①現在の言葉では、XまたはYはNよりも大きい、つまり嘘であり、これは最も簡単に判断でき、必要なだけですif(x>n || y>n) ans++;
。
②現在の言葉が以前の真実と矛盾する、またはxを食べるxの出現は嘘であり、実際、xを食べるxの存在は真実との矛盾です。
したがって、私たちは正しい関係を決定できるすべての動物をセットに入れることができます最初は、各動物が自分自身を食べないことがわかっているだけなので、各動物がセットを形成します。
次に、セットでは、現在のノードからセットのルートノードまでの距離を維持する必要がありますd[i]
。動物は3種類しかないため、各動物のカテゴリを使用しkind[i] = d[i]%3
て、特定のセット内の動物の状態関係を表すことができます。種類= 1 0,2 1,0食べる食べる食べる2なので、kind[i]%3 == kind[j]%3
iとjが同じ種のkind[i]%3 == kind[j]%3
とき、食べるときはjを表します。
これはコレクションのマージとクエリであるため、当然、ユニオン検索コレクションが使用されますが、維持する必要があるのは距離パラメーターのみです。
質問された2つの種が同じセットにない場合、それは2匹の動物間の関係が未定であることを意味します。現在の単語は真実であり、矛盾はありません。2つのセットは現在の単語に従ってマージされます。
距離に関する更新
if(x和y同类)
(d[sy]+d[y])%3 = d[x]%3
即d[sy] = (d[x]%3+d[y]%3+3)%3
if(x吃y)
d[x]%3 = (d[sy] +d[y]+1)%3
d[sy] = (d[x]%3-d[y]%3-1+3)
問題の2つの種が同じコレクションにある場合、それらは真実と矛盾する可能性があります。
非冲突状态
同类:d[x] %3 == d[y]%3
x吃y: d[x]%3 == (d[y]+1)%3
C ++コードの実装
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 5e4+10;
int n, k;
int p[N], d[N];//p是并查集的集合,d[i]是i到根节点的距离
//带有路径压缩的并查集查找
int find(int x) {
if(x != p[x]) {
int t = p[x];
p[x] = find(p[x]);
d[x] += d[t];//将整个路径的距离加在一起就是当前节点到根节点的距离
}
return p[x];
}
int main() {
cin>>n>>k;
//初始化集合
for(int i = 1; i < n; ++i) {
p[i] = i;
}
int ans= 0;
while(k--) {
int D, x, y;
scanf("%d%d%d", &D, &x, &y);
if(x > n || y > n) {
ans++;
continue;
}
int sx = find(x);
int sy = find(y);
//只有在同一个集合才有可能冲突
if(sx == sy) {
//int dif = (d[x]%3 - d[y]%3 + 3)%3;
if(D == 1) {
if(d[x]%3 != d[y]%3) {
ans++;
}
}
else {
if(d[x]%3!= (d[y]+1)%3) {
ans++;
}
}
}
else{
//不会冲突,合并两个集合
p[sy] = sx;
//1-->0, 2-->1, 3-->2
//(d[y]+d[sy])%3 = d[x]%3
//d[sy] = d[x]-d[y];
if(D == 1) {
d[sy] = (d[x]%3-d[y]%3+3)%3;
}
else{
//(d[y]+d[sy])%3-d[x]%3 = 1
d[sy] = (d[x]%3-d[y]%3-1+3)%3;
}
}
}
cout<<ans<<endl;
return 0;
}