题目链接:【POJ 1182】食物链
父节点跟子节点之间一共有三种关系,父节点吃子节点,子节点吃父节点,父节点跟子节点是同类,所以用三进制表示
fa[B]=A,rank[B]=0表示与父节点是同类,rank[B]=1表示被父节点吃,rank[B]=2表示吃父节点
一共分两大类进行操作:1、x跟y的父节点相同 2、x跟y的父节点不同
下面是我做题时画的图,方便理解,父节点跟子节点之间的关系有9种,箭头指出去的表示被吃,箭头指进来的表示吃父节点
1、x跟y的父节点相同
只有满足(rank[y]-rank[x]+3)%3==id-1时,那输入的id x y这句话才是真的
2、x跟y的父节点不相同
xi是x的父节点,yi是y的父节点
黑线表示父节点跟子节点之间的关系
1) id=1,x跟y是同一类
2) id=2,x吃y
通过画图可以发现,当父节点不同时都是真话(除了id=2&&x==y),需要我们做的就是找到相应的xi与yi间的关系,更新节点权值
fa[yi] = xi && rank[yi]=(rank[x]-rank[y]+id+3)%3
上面的纯粹是理解用的,理论知识可以点击这里
当然,要是公式总结不出来,直接通过上图用if else来判断也是可以的,就是麻烦了点
#include
#include
#include
#include
#include
using namespace std;
const int N=50001;
int fa[N], rank[N];
void init(int n)
{
for(int i=1; i<=n; i++)
{
fa[i]=i, rank[i]=0;
}
}
int find(int x)
{
if(x!=fa[x])
{
int fx=find(fa[x]);
rank[x]=(rank[x]+rank[fa[x]])%3;
fa[x]=fx;
}
return fa[x];
}
bool Union(int id, int x, int y)
{
int xi=find(x), yi=find(y);
if(xi==yi)
{
if((rank[y]-rank[x]+3)%3==id) return false;
return true;
}
fa[yi] = xi;
rank[yi]=(rank[x]-rank[y]+id+3)%3;
return false;
}
int main()
{
int n, k, id, x, y, ans=0;
scanf("%d%d", &n, &k);
init(n);
while(k--)
{
scanf("%d%d%d", &id, &x, &y);
if(x>n || y>n || (x==y&&id==2)) ans++;
else if(Union(id-1, x, y)) ans++;
}
printf("%d\n", ans);
return 0;
}
题目链接:【POJ 1733】 Parity game
题目链接:【POJ 2492】 A Bug's Life
题目链接:【POJ 1703】 Find them, Catch them
题目链接:【POJ 1988】 Cube Stacking
题目链接:【POJ 2912】 Rochambeau
题目链接:【HDU 3038】 How Many Answers Are Wrong
有n个数,m次询问,给出a到b区间的总和s,问这m次给出的总和中有几次是和前面已近给出的是矛盾的
sum[i]记录的是i到根节点的区间和,fa[i]记录的根节点永远比i小
输入注意要加while(~scanf("")),否则会wa!
#include
#include
#include
#include
#include
using namespace std;
const int N=1e5+10;
int fa[2*N], sum[2*N];
int find(int x)
{
if(x!=fa[x])
{
int fx=find(fa[x]);
sum[x]+=sum[fa[x]];
fa[x]=fx;
}
return fa[x];
}
bool Union(int a, int b, int s)
{
int ai=find(a), bi=find(b);
if(ai==bi)
{
if(sum[a]+s != sum[b]) return true;
}
else //这里画画图就能得出结论
{
if(ai>bi)
{
fa[ai]=bi;
sum[ai]=sum[b]-sum[a]-s;
}
else
{
fa[bi]=ai;
sum[bi]=sum[a]+s-sum[b];
}
}
return false;
}
int main()
{
int n, m, a, b, s;
while(~scanf("%d%d", &n, &m))
{
int ans=0;
for(int i=0; i<=n; i++) fa[i]=i, sum[i]=0;
while(m--)
{
scanf("%d%d%d", &a, &b, &s);
if(Union(a-1, b, s)) ans++;
}
printf("%d\n", ans);
}
return 0;
}
题目链接:【HDU 3047】 Zjnu Stadium