POJ 1182 食物链 [并查集 带权并查集 开拓思路]
Time Limit:1000MS Memory Limit:10000KB 64bit IO Format:%I64d & %I64u
System Crawler (2015-01-27)
Description
现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。
有人用两种说法对这N个动物所构成的食物链关系进行描述:
第一种说法是"1 X Y",表示X和Y是同类。
第二种说法是"2 X Y",表示X吃Y。
此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。
1) 当前的话与前面的某些真的话冲突,就是假话;
2) 当前的话中X或Y比N大,就是假话;
3) 当前的话表示X吃X,就是假话。
你的任务是根据给定的N(1 <= N <= 50,000)和K句话(0 <= K <= 100,000),输出假话的总数。
Input
以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。
若D=1,则表示X和Y是同类。
若D=2,则表示X吃Y。
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
先吐槽一下关于多组样例的问题,闲话也不多说,这题网上大牛各种神奇的题解都有,第一份代码是常规带权并查集的做法,不多谈,我主要想谈一下第二份代码的思路。
如果我们换一个思路,把1--n看成与自身同类的集合,1+n--2*n看成自己吃的集合,1+2*n--3*n看成吃自己的集合,那么问题便简单多了~~~
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<string> #define N 50005
#define M 105
#define mod 1000000007
//#define p 10000007
#define mod2 1000000000
#define ll long long
#define LL long long
#define eps 1e-6
#define inf 100000000
#define maxi(a,b) (a)>(b)? (a) : (b)
#define mini(a,b) (a)<(b)? (a) : (b) using namespace std; int n,m;
int f[N];
int r[N];
int ans; void ini()
{
ans=;
int i;
for(i=;i<=n;i++){
f[i]=i;
r[i]=;
}
} int find(int x)
{
int fa;
if(f[x]!=x)
{
fa=find(f[x]);
r[x]=(r[x]+r[ f[x] ])%;
f[x]=fa;
}
return f[x];
} void merge(int x,int y,int d)
{
int a,b;
a=find(x);
b=find(y);
if(a==b){
return;
}
f[b]=a;
r[b]=(-r[y]+r[x]+d)%;
} void solve()
{
int d,x,y;
int a,b;
int re;
int i;
for(i=;i<=m;i++){
scanf("%d%d%d",&d,&x,&y);
if(x>n || y>n){
ans++;continue;
}
if(d== && x==y){
ans++;continue;
}
a=find(x);
b=find(y);
re=(-r[x]+r[y])%;
if(a==b && re!=d-){
ans++;continue;
}
//printf(" i=%d\n",i);
merge(x,y,d-);
}
} void out()
{
printf("%d\n",ans);
} int main()
{
//freopen("data.in","r",stdin);
//freopen("data.out","w",stdout);
//scanf("%d",&T);
//for(int ccnt=1;ccnt<=T;ccnt++)
//while(T--)
//while(scanf("%d%d",&n,&m)!=EOF)
scanf("%d%d",&n,&m);
{
ini();
solve();
out();
}
return ;
}
如果我们换一个思路,把1--n看成与自身同类的集合,1+n--2*n看成自己吃的集合,1+2*n--3*n看成吃自己的集合,那么问题便简单多了~~~
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<string> #define N 50005
#define M 105
#define mod 1000000007
//#define p 10000007
#define mod2 1000000000
#define ll long long
#define LL long long
#define eps 1e-6
#define inf 100000000
#define maxi(a,b) (a)>(b)? (a) : (b)
#define mini(a,b) (a)<(b)? (a) : (b) using namespace std; int n,m;
int f[*N];
int ans; void ini()
{
ans=;
int i;
for(i=;i<=*n;i++){
f[i]=i;
}
} int find(int x)
{
int fa;
if(f[x]!=x)
{
fa=find(f[x]);
f[x]=fa;
}
return f[x];
} void merge(int x,int y)
{
int a,b;
a=find(x);
b=find(y);
if(a==b){
return;
}
f[b]=a;
} void solve()
{
int d,x,y;
int a,b;
int fx,sx;
int i;
for(i=;i<=m;i++){
scanf("%d%d%d",&d,&x,&y);
if(x>n || y>n){
ans++;continue;
}
if(d== && x==y){
ans++;continue;
}
a=find(x);
b=find(y);
fx=find(x+n);
sx=find(x+*n);
if(d==){
if(b==fx || b==sx){
ans++;continue;
}
else{
merge(x,y);
merge(x+n,y+n);
merge(x+*n,y+*n);
}
}
else{
if(b==a || b==sx){
ans++;continue;
}
else{
merge(x+n,y);
merge(x+*n,y+n);
merge(x,y+*n);
}
}
}
} void out()
{
printf("%d\n",ans);
} int main()
{
//freopen("data.in","r",stdin);
//freopen("data.out","w",stdout);
//scanf("%d",&T);
//for(int ccnt=1;ccnt<=T;ccnt++)
//while(T--)
//while(scanf("%d%d",&n,&m)!=EOF)
scanf("%d%d",&n,&m);
{
ini();
solve();
out();
}
return ;
}
POJ 1182 食物链 [并查集 带权并查集 开拓思路]的更多相关文章
- poj 1182 食物链(高级的带权并查集)
食物链 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 76486 Accepted: 22742 Description ...
- 浅谈并查集&种类并查集&带权并查集
并查集&种类并查集&带权并查集 前言: 因为是学习记录,所以知识讲解+例题推荐+练习题解都是放在一起的qvq 目录 并查集基础知识 并查集基础题目 种类并查集知识 种类并查集题目 并查 ...
- 【POJ 1984】Navigation Nightmare(带权并查集)
Navigation Nightmare Description Farmer John's pastoral neighborhood has N farms (2 <= N <= 40 ...
- Poj1182 食物链(并查集/带权并查集)
题面 Poj 题解 这里采用并查集的补集. \(x\)表示同类集合,\(x+n\)表示敌人集合,\(x+n\times2\)表示敌人的敌人集合. 如果当前给出的是一对同类关系,就判断\(x\)是否吃\ ...
- POJ 1984 Navigation Nightmare 【经典带权并查集】
任意门:http://poj.org/problem?id=1984 Navigation Nightmare Time Limit: 2000MS Memory Limit: 30000K To ...
- [poj 2912] Rochambeau 解题报告 (带权并查集)
题目链接:http://poj.org/problem?id=2912 题目: 题目大意: n个人进行m轮剪刀石头布游戏(0<n<=500,0<=m<=2000) 接下来m行形 ...
- poj 1733 Parity game【hash+带权并查集】
hash一下然后用带权并查集做模2下的前缀和 #include<iostream> #include<cstdio> #include<map> #include& ...
- POJ 2492 A Bug's Life 带权并查集
题意: 思路: mod2 意义下的带权并查集 如果两只虫子是异性恋,它们的距离应该是1. 如果两只虫子相恋且距离为零,则它们是同性恋. (出题人好猥琐啊) 注意: 不能输入一半就break出来.... ...
- POJ 2492 A Bug's Life (带权并查集 && 向量偏移)
题意 : 给你 n 只虫且性别只有公母, 接下来给出 m 个关系, 这 m 个关系中都是代表这两只虫能够交配, 就是默认异性, 问你在给出的关系中有没有与异性交配这一事实相反的, 即同性之间给出了交配 ...
随机推荐
- 高精度A+B
#include<stdio.h> #include<string.h> int main() { int lenth1,lenth2,n,i,j,k,s; scanf(&qu ...
- WebStorm 编辑器 关闭自动保存功能及添加*星星标记
WebStorm 关闭自动保存功能添加*星星标记为什么要关闭自动保存? 在前端项目工作当中,往往会采用自动化环境(Gulp.webpack等)当文本发生变化的时候就会自动编译代码.在we ...
- vuejs 中 select 动态填充数据,后台的数据
selected:"A" 对 selected:A 错. 变量不用引号. 内容一定要引号. https://jsfiddle.net/rgnuaw30/ ...
- oracle row_number的使用
create table studentInfo( id number(8) primary key, name varchar2(20) not null, ObjectName varcha ...
- js 一维数组转成tree 对象
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- python中enumerate()函数的用法
描述: enumerate() 函数用于将一个可遍历的数据对象(如列表.元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中.其英文意为:枚举,列举. 函数说明: 语法 ...
- 四、10分钟ToPandas_0.24.2
# Author:Zhang Yuan整理,版本Pandas0.24.2 # 0. 习惯上,我们会按下面格式引入所需要的包: import pandas as pd import numpy as n ...
- fork()函数,一次调用,两次返回
参考自:http://blog.csdn.net/dog_in_yellow/archive/2008/01/13/2041079.aspx 以前一直迷惑,什么叫一次调用,两次返回.通过上网搜索,终于 ...
- git 打补丁,即git review之后需要二次修改并提交代码
假如代码已经push上去了,可是当review时,发现有地方需要修改,你可以继续在本地修改你的文件,之后git status查看修改的文件,然后git add修改的文件,此时不能直接git commi ...
- CodeForces 149D 区间DP Coloring Brackets
染色有三个条件: 对于每个点来说要么不染色,要么染红色,要么染蓝色 对于每对配对的括号来说,有且只有一个一边的括号被染色 相邻的括号不能染成相同的颜色 首先可以根据给出的括号序列计算出括号的配对情况, ...