http://poj.org/problem?id=1182
如题。忘了参照哪个大神的blog了...莫怪-,-
设两个数组:rela[x]:表示x与其父节点的关系,pre[x],表示x的父节点。
至于神马向量公式的,通过rela[x]与rela[y]的关系与D做比较判断是否说谎
cqlf 1182 Accepted 1080K 266MS G++ 966B 2012-03-21
23:57:17
#include<iostream> #include<cstdio> #include<cstring> using namespace std; #define MAXN 50005 int N; int pre[MAXN],rela[MAXN];//pre:parent of i,rela:relation between i and i's parent void UFset() { int i; for(i=1;i<=N;i++) { pre[i]=i; rela[i]=0; } } int find(int x) { int s; if(x==pre[x]) return x; s=find(pre[x]); rela[x]=(rela[x]+rela[pre[x]])%3; return pre[x]=s; } int Union(int R1,int R2,int D) { int r1=find(R1); int r2=find(R2); if(r1==r2)// same type { if((rela[R2]-rela[R1]+3)%3!=D)//judge the result equal type or not return 1; else return 0; } else { pre[r2]=r1; rela[r2]=(rela[R1]-rela[R2]+D+3)%3; return 0; } } int main() { int K; int D,X,Y; int i; int num=0; scanf("%d%d",&N,&K); UFset(); for(i=1;i<=K;i++) { scanf("%d%d%d",&D,&X,&Y); if(X>N||Y>N||(X==Y&&D==2)) {num++;continue;} if(Union(X,Y,D-1)) num++; } printf("%d\n",num); return 0; }
今天是2012年8月30号。把这道并查集重新拿出来专题训练,当初做这题时是参考别人做的.不懂什么种类并查集.
所谓种类并查集:除了pre数组记录每个结点与根结点的关系,子树与新父亲结点的关系在路劲压缩时更改。
此题可根据几组数据推出一个规律:
rela[x]=(rela[x]+rela[pre[x]])%3;
这是路径压缩时,子树与新父亲结点的更新。
在合并两个结点时,判断两个根节点是否相同.
相同的话说明之前有关系就判断下关系是否等于现在的关系.
(rela[R1]-rela[R2]+3)%3!=D
不相同就加进集合,修改rela[x]属性
pre[r1]=r2;
rela[r1]=(rela[R2]-rela[R1]+D+3)%3;
/*
Problem ID:G - 食物链
meaning:
Analyzing:种类并查集,
*/
#include <iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<vector>
using namespace std;
typedef struct even{int pi,di;}even;
#define FOR(i,s,t) for(int i=(s); i<(t); i++)
#define LL long long
#define maxn 50005
int pre[maxn],rela[maxn];
int N,K,D;
int num;
void init(){
for(int i=0;i<maxn;i++){
pre[i]=-1;
rela[i]=0;
}
}
int find(int x){
int s=x;
if(pre[x]<0) return x;
s=find(pre[x]);
rela[x]=(rela[x]+rela[pre[x]])%3;
return pre[x]=s;
}
void Union(int R1,int R2){
int r1=find(R1);
int r2=find(R2);
if(r1==r2) {
if((rela[R1]-rela[R2]+3)%3!=D) num++;
}
else {
pre[r1]=r2;
rela[r1]=(rela[R2]-rela[R1]+D+3)%3;
}
}
int main(){
int X,Y;
scanf("%d%d",&N,&K);
num=0;
init();
while(K--){
scanf("%d%d%d",&D,&X,&Y);
if(X>N||Y>N||(X==Y&&D==2)) {num++;continue;}
if(D==1&&X==Y) continue;
D--;
Union(X,Y);
}
printf("%d\n",num);
return 0;
}