http://poj.org/problem?id=1182
pre构建有关系的号码的树,rel保存当前号码与根的关系,0表示相同,1表示根吃当前,2表示当前吃根。
代码中的更新公式可以先把各种情况枚举出来,然后就能推出来了。
#include<iostream> #include<cstring> #include<cstdio> using namespace std; int pre[50005],rel[50005]; //0:当前与根同类 //1:根吃当前 //2:当前吃根 int findd(int x) { if(pre[x] == x) return x; int root = findd(pre[x]); rel[x] = (rel[x]+rel[pre[x]])%3; pre[x] = root; return root; } int join(int d,int x,int y) { int xx = findd(x),yy = findd(y); if(xx == yy) { if(d == 1 && rel[x] != rel[y]) return 1; else if(d == 2 && rel[y] != (rel[x]+1)%3) return 1; else return 0; } pre[yy] = xx; rel[yy] = (rel[x]-rel[y]+d+2)%3; return 0; } int main() { int n,m; scanf("%d%d",&n,&m); for(int i = 1;i <= n;i++) pre[i] = i,rel[i] = 0; int ans = 0; int d,x,y; while(m--) { scanf("%d%d%d",&d,&x,&y); if(x > n || y > n) ans++; else if(d == 2 && x == y) ans++; else if(join(d,x,y)) ans++; } printf("%d ",ans); return 0; }