拆点法

用并查集维护每种动物的同类、天敌、食物群

#include<cstdio>
int fa[300005];
int n,k,ans;
inline int read()
{
int sum=0;
char ch=getchar();
while(ch>'9'||ch<'0') ch=getchar();
while(ch>='0'&&ch<='9') sum=sum*10+ch-48,ch=getchar();
return sum;
}//读入优化
int find(int x)
{
if(x!=fa[x]) fa[x]=find(fa[x]);
return fa[x];
}//查询
int unity(int x,int y)
{
int r1=find(fa[x]),r2=find(fa[y]);
fa[r1]=r2;
}//合并
int main()
{
int x,y,z;
n=read(),k=read();
for(int i=1;i<=3*n;++i) fa[i]=i; //对于每种生物:设 x 为本身,x+n 为猎物,x+2*n 为天敌
for(int i=1;i<=k;++i)
{
z=read(),x=read(),y=read();
if(x>n||y>n) {ans++; continue;} // 不属于该食物链显然为假
if(z==1)
{
if(find(x+n)==find(y)||find(x+2*n)==find(y)) {ans++; continue;}
//如果1是2的天敌或猎物,显然为谎言
unity(x,y); unity(x+n,y+n); unity(x+2*n,y+2*n);
//如果为真,那么1的同类和2的同类,1的猎物是2的猎物,1的天敌是2的天敌
}
else if(z==2)
{
if(x==y) {ans++; continue;} //其实是废话但是可以稍微省点时间
if(find(x)==find(y)||find(x+2*n)==find(y)) {ans++; continue;}
//如果1是2的同类或猎物,显然为谎言
unity(x,y+2*n); unity(x+n,y); unity(x+2*n,y+n);
//如果为真,那么1的同类是2的天敌,1的猎物是2的同类,1的天敌是2的猎物
}
}
printf("%d\n",ans);
return 0;
}

带权并查集法

  • 如果X、Y是同类,可以用并查集并起来
  • 但如果对于A、B、C三类分开保存,会存在一定问题
  • 因为A、B、C之间存在着连续关系,比如A吃B、B吃C、C吃D,其实可以推导出A、D为同类
  • 考虑将关系建成一张图,两个点之间路径的权值由关系决定。
  • 如果u、v是同类,那么u->v路径权值为0
  • 如果u吃v,那么u->v路径权值为1
  • 如果v吃u,那么u->v路径权值为2
  • 那么两个点之间的关系可以由两个点之间的路径得出(模3)。
  • 但每次查询时找路径会有一个O(N)的复杂度
  • 发现两个点之间的所有路径权值都是一样的,所以只需要保留一条
  • 两个点之间的关系由这个权值来表示
  • 知道了两个点分别与根的关系,就可以知道两个点之间的关系
  • 带权并查集压缩路径的时候需要考虑当前点到新根的距离
  • 复杂度O(K*alpha(N))
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<ctime>
#include<iostream>
#include<string>
#include<vector>
#include<list>
#include<deque>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<algorithm>
#include<complex>
#pragma GCC optimize ("O0")
using namespace std;
template<class T> inline T read(T&x){
T data=0;
int w=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')
w=-1;
ch=getchar();
}
while(isdigit(ch))
data=10*data+ch-'0',ch=getchar();
return x=data*w;
}
typedef long long ll;
const int INF=0x7fffffff; const int MAXN=1e5+7; int fa[MAXN],val[MAXN]; int find(int x)
{
if(fa[x]==x)
return x;
else
{
int fx=fa[x];
fa[x]=find(fa[x]);
val[x]=(val[x]+val[fx])%3;
return fa[x];
}
} int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
int n,k;
read(n);read(k);
for(int i=1;i<=n;++i)
fa[i]=i,val[i]=0;
int ans=0;
while(k--)
{
int opt,x,y;
read(opt);read(x);read(y);
if(x>n||y>n)
{
++ans;
continue;
}
if(opt==1)
{
int fx=find(x),fy=find(y);
if(fx==fy)
{
if((val[x]+3-val[y])%3!=0)
++ans;
}
else
{
fa[fx]=fy;
val[fx]=3-(val[x]+3-val[y])%3;
}
}
else if(opt==2)
{
if(x==y)
{
++ans;
continue;
}
int fx=find(x),fy=find(y);
if(fx==fy)
{
if((val[x]+3-val[y])%3!=1)
++ans;
}
else
{
fa[fx]=fy;
val[fx]=4-(val[x]+3-val[y])%3;
val[fx]%=3;
}
}
}
printf("%d\n",ans);
// fclose(stdin);
// fclose(stdout);
return 0;
}

LG2024 [NOI2001]食物链的更多相关文章

  1. NOI2001 食物链【扩展域并查集】*

    NOI2001 食物链 动物王国中有三类动物 A,B,C,这三类动物的食物链构成了有趣的环形.A 吃 B,B吃 C,C 吃 A. 现有 N 个动物,以 1 - N 编号.每个动物都是 A,B,C 中的 ...

  2. 洛谷 P2024 [NOI2001]食物链 解题报告

    P2024 [NOI2001]食物链 题目描述 动物王国中有三类动物 A,B,C,这三类动物的食物链构成了有趣的环形.A 吃 B,B 吃 C,C 吃 A. 现有 N 个动物,以 1 - N 编号.每个 ...

  3. 【题解】P2024 [NOI2001]食物链 - 数据结构 - 并查集

    P2024 [NOI2001]食物链 声明:本博客所有题解都参照了网络资料或其他博客,仅为博主想加深理解而写,如有疑问欢迎与博主讨论✧。٩(ˊᗜˋ)و✧*。 题目描述 动物王国中有三类动物 \(A,B ...

  4. NOI2001 食物链

    食物链 题目描述 动物王国中有三类动物 A,B,C,这三类动物的食物链构成了有趣的环形.A 吃 B,B 吃 C,C 吃 A. 现有 N 个动物,以 1 - N 编号.每个动物都是 A,B,C 中的一种 ...

  5. P2024 [NOI2001]食物链 并查集

    题目描述 动物王国中有三类动物 A,B,C,这三类动物的食物链构成了有趣的环形.A 吃 B,B 吃 C,C 吃 A. 现有 N 个动物,以 1 - N 编号.每个动物都是 A,B,C 中的一种,但是我 ...

  6. 洛谷 P2024 [NOI2001]食物链 (并查集)

    嗯... 题目链接:https://www.luogu.org/problemnew/show/P2024 这道题和团伙这道题的思想比较类似,都是一个数组分成几个集合,但这道题的思路更加混乱,建议没做 ...

  7. NOI2001食物链

    描述 动物王国中有三类动物 A,B,C,这三类动物的食物链构成了有趣的环形.A吃B,B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种. 有人 ...

  8. [NOI2001] 食物链 (扩展域并查集)

    题目描述 动物王国中有三类动物 A,B,C,这三类动物的食物链构成了有趣的环形.A 吃 B,B 吃 C,C 吃 A. 现有 N 个动物,以 1 - N 编号.每个动物都是 A,B,C 中的一种,但是我 ...

  9. 洛谷 P2024 [NOI2001]食物链

    题意简述 有人用两种说法对这 N 个动物所构成的食物链关系进行描述: 1."1 X Y",表示 X 和 Y 是同类. 2."2 X Y",表示 X 吃 Y . ...

随机推荐

  1. English trip -- VC(情景课) 7 C How much are the shose? 鞋多少钱

    Grammar focus 语法点: How much is ...? How much are...? How much is the shirt?    $15.99. How much are ...

  2. Confluence 6 导入 Active Directory 服务器证书 - UNIX

    为了让你的应用服务器能够信任你的目录服务器.你目录服务器上导出的证书需要导入到你应用服务器的 Java 运行环境中.JDK 存储了信任的证书,这个存储信任证书的文件称为一个 keystore.默认的 ...

  3. CF1082G Petya and Graph

    题意 定义图权 = 图中边权总和 - 图中点权总和(空图的图权=0),求 n 个点 m 条边的无向图最大权子图. 把边看成点,这个点与两个原图中的点连边.直接最小割求最大闭合子图即可.

  4. 4.1 delegate

    delegate  ---packed up function public delegate double myDelegate (double x); my delegate d2 = new m ...

  5. Pandas DataFrame 数据选取和过滤

    This would allow chaining operations like: pd.read_csv('imdb.txt') .sort(columns='year') .filter(lam ...

  6. sql语句:查询、排序、不区分大小写查询,及联合使用

    1.不排序时的查找语句: offset message  为表名,talker 为列名. 此语句的意思是:从message 表中查找 talker 等于wxid_0930479303212的数据,从第 ...

  7. substr和substring,slice和splice的区别,js字符串截取和数组截取

    本文参考了文章:https://blog.csdn.net/kenberkeley/article/details/50983734 博主已经总结得很好了,看完之后也能明白,不过还是觉得要自己动手敲一 ...

  8. PHP:第四章——PHP数组array_diff计算数组差集

    <pre> <?php header("Content-Type:text/html;charset=utf-8"); /*知识点一:array_diff — 计 ...

  9. learning uboot enable protect console

    reference :https://github.com/lentinj/u-boot/blob/master/doc/README.autoboot how to enable protect s ...

  10. Openwrt WiFi Configure(1)

    1      Scope of Document This document describes how to custom wifi option 2      Requiremen 2.1     ...