题目:洛谷p2024
题意描述:给你n种动物,r个关系(同类,猎物,天敌),判断有多少句假话。
这道题一开始没太懂怎么去做。。。想到了并查集但没有好的思路去判别这三种关系,直到看了题解,有一个大佬开了3倍并查集来做。。。开启了新世纪的大门(这也行。。。)
下面上代码
1 #include <bits/stdc++.h> 2 #define fi first 3 #define se second 4 #define pb push_back 5 #define fio ios::sync_with_stdio(false);cin.tie(0); 6 #define pii pair<int,int> 7 #define vi vector<int> 8 #define vc vector<char> 9 #define mii map<int,int> 10 #define si(a) scanf("%d",&a) 11 #define ss(a) scanf("%s",&a) 12 #define sl(a) scanf("%I64d",&a); 13 #define slf(a) scanf("%lf",&a); 14 #define CLEAR(a,b) memset(a,b,sizeof(a)) 15 #define pi acos(-1) 16 typedef long long ll; 17 typedef unsigned long long ull; 18 typedef double db; 19 const int INF=0x3f3f3f3f; 20 const int N=3e5+5; 21 using namespace std; 22 23 priority_queue< int,vector<int>,greater<int> > pqg; 24 priority_queue< int,vector<int>,less<int> > pql; 25 26 int pre[N];//记录各个点的上一个节点,如果自己是老大就等于自己 27 28 int Find(int n)//查找根节点 29 { 30 int r=n; 31 while(pre[r]!=r)//查找这个点的根节点 32 { 33 r=pre[r]; 34 } 35 //r现在是根节点 36 int i=n,j; 37 while(i!=r)//路径压缩,让小弟直接归老大直辖 38 { 39 j=pre[i]; 40 pre[i]=r; 41 i=j; 42 } 43 return r; 44 } 45 46 void join(int x,int y)//把各个连同分支连起来 47 { 48 int r1=Find(x); 49 int r2=Find(y); 50 if(r1!=r2)//如果已经连通不用管 51 { 52 pre[r1]=r2;//不连通的时候随便指定一个是另一个的老大 53 } 54 } 55 56 int main() 57 { 58 int n,r; 59 si(n);si(r); 60 for (int i=1;i<=3*n;i++)//1是同类,2是食物,3是天敌 61 pre[i]=i; 62 int ans=0; 63 for (int i=1;i<=r;i++) 64 { 65 int a,b,c; 66 cin>>a>>b>>c; 67 if(b>n||c>n) {ans++;continue;} 68 if(a==1) 69 { 70 if(Find(b+n)==Find(c)||Find(b+2*n)==Find(c)) 71 { 72 ans++; 73 continue; 74 } 75 join(b,c);join(b+n,c+n);join(b+2*n,c+2*n); 76 } 77 else if(a==2) 78 { 79 if(Find(b)==Find(c)||Find(b+2*n)==Find(c)) 80 { 81 ans++; 82 continue; 83 } 84 join(b,c+2*n);join(b+n,c);join(b+2*n,c+n); 85 } 86 } 87 cout<<ans<<endl; 88 }