Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 35508 | Accepted: 10334 |
Description
Input
Output
Sample Input
100 7 1 101 1 2 1 2 2 2 3 2 3 3 1 1 3 2 3 1 1 5 5
Sample Output
3
此题是个并查集
对于任意一种新关系(a,b,c),首先查看b、c之间是否存在关系:若存在,则将该已存在的关系与要建立的关系比较,看是否为假话(若为假话,则计数器加1),若为真话或关系不存在,则直接建立新的关系
par[a]表示a的父亲节点,relation[a]表示a与其父亲结点的关系,其中relation[a]为0表示a与其父亲结点同类,为1表示其父亲吃a,为2表示a吃其父亲
初始化par[a]=a,relation[a]=0
int Get_par(int a)
//压缩路径,返回a的父亲节点 { if(par[a]==a) return par[a]; int r=par[a]; par[a]=Get_par(par[a]); relation[a]=(relation[a]+relation[r])%3;//通过a与其父亲节点以及其父亲节点与根节点的关系来建立a与根节点的关系,a吃b,b吃c,则c吃a return par[a]; }
void Merge(int a,int b,int r) //建立a与b的关系r { int pa,pb; pa=Get_par(a); pb=Get_par(b); par[pa]=pb; relation[pa]=(r+3+relation[b]-relation[a])%3;//通过a,b与其各自的父亲节点pa,pb的关系以及a与b的关系,来确定pa与pb的关系,具体的推到读者自己慢慢琢磨 }
#include<iostream> #include<cstdio> using namespace std; int const MAX=50000+10; int n,k; int par[MAX]; int relation[MAX]; //0表示同类,1表示父亲节点吃他,2表示他吃父亲节点 int Get_par(int a) { if(par[a]==a) return par[a]; int r=par[a]; par[a]=Get_par(par[a]); relation[a]=(relation[a]+relation[r])%3; return par[a]; } void Merge(int a,int b,int r) { int pa,pb; pa=Get_par(a); pb=Get_par(b); par[pa]=pb; relation[pa]=(r+3+relation[b]-relation[a])%3; } int main() { int i,a,b,c,ans,pb,pc; scanf("%d%d",&n,&k); ans=0; for(i=1;i<=n;i++) { par[i]=i; relation[i]=0; } for(i=0;i<k;i++) { scanf("%d%d%d",&a,&b,&c); if(b>n||c>n) //当前的话中X或Y比N大,就是假话 { ans++; continue; } else if(a==2&&b==c) //当前的话表示X吃X,就是假话 { ans++; continue; } pb=Get_par(b); pc=Get_par(c); if(pb!=pc) //建立一种新关系 { Merge(b,c,a-1); } else { if((3+relation[b]-relation[c])%3!=a-1) ////当前的话与前面的某些真的话冲突,就是假话 { ans++; continue; } } } printf("%d\n",ans); return 0; }