[题解]NOI 2001 食物链

发个题目链接吧

http://www.cqoi.net:2012/JudgeOnline/problem.php?id=1356

【题解】

在高一妹纸的推荐下看的这道题,发现NOI竟然有水题啊啊,果断水过~~~ 因为zyy语言组织能力不强,应妹纸要求,写个题解,大神请绕道。

下面进入正题。

首先是维护信息。我们不能直接确定A、B、C,但我们可以找他们之间的关系。x吃y,那么就fa[y]=x; 维护一个三角环,对于三角环的每一个角表示同类(并查集)。

然后就是判断假话。2、3两个条件都是O(1)判断的,吴老师肯定会说:wtt都会做。。。orz  所以这里不赘述。考虑第1个判断,下面分情况讨论。

if(x、y是同类)

{

  找到x所在环上的元素a[0],a[1],a[2],y所在环上的元素b[0],b[1],b[2]。

  if(x、y在同一个环上)

  {  

    if(x==y)  同类

    else  假话

  }

  else  合并

}

else

{

  找到x所在环上的元素a[0],a[1],a[2],y所在环上的元素b[0],b[1],b[2]。

  if(x、y在同一个环上)

  {

    if(fa[b[0]]==a[0]) 真话

    else  假话

  }

  else 合并

}

zyy好像还是木有说清楚的说。。。 所以还是上代码吧。。。。

View Code
 1 #include<iostream> 
 2 #include<cstdio> 
 3 using namespace std; 
 4 #define MAXN 50020 
 5 int p[MAXN*3],fa[MAXN*3]; 
 6 int a[4],b[4]; 
 7 int n,m; 
 8 int ans; 
 9 bool flag; 
10 inline void Get_int(int &Ret) 
11 { 
12     char ch; 
13     bool flag=false; 
14     for(;ch=getchar(),ch<'0'||ch>'9';) 
15         if(ch=='-') 
16             flag=true; 
17     for(Ret=ch-'0';ch=getchar(),ch>='0'&&ch<='9';Ret=Ret*10+ch-'0'); 
18     flag&&(Ret=-Ret); 
19 } 
20 void Pre() 
21 { 
22     Get_int(n); 
23     int i; 
24     for(i=1;i<=n;i++) 
25     { 
26         fa[i]=i+n,fa[i+n]=i+n*2,fa[i+n*2]=i; 
27         p[i]=i,p[i+n]=i+n,p[i+n*2]=i+n*2; 
28     } 
29 } 
30 int Find(int x) 
31 { 
32     if(x!=p[x]) 
33         p[x]=Find(p[x]); 
34     return p[x]; 
35 } 
36 void Work() 
37 { 
38     Get_int(m); 
39     int d,x,y; 
40     int i,j,k; 
41     for(i=1;i<=m;i++) 
42     { 
43         Get_int(d),Get_int(x),Get_int(y); 
44         if(x>n||y>n) 
45         { 
46             ans++; 
47             continue; 
48         } 
49         a[0]=Find(x),a[1]=fa[a[0]],a[2]=fa[a[1]]; 
50         b[0]=Find(y),b[1]=fa[b[0]],b[2]=fa[b[1]]; 
51         flag=false; 
52         for(j=0;j<=2;j++) 
53             if(a[0]==b[j]) 
54             { 
55                 k=j; 
56                 flag=true; 
57                 break; 
58             } 
59         if(d==1)//the same 
60         { 
61             if(flag)//in a triangle 
62             { 
63                 if(a[0]!=b[0]) 
64                     ans++; 
65             } 
66             else
67             { 
68                 for(j=0;j<=2;j++) 
69                     p[b[j]]=a[j]; 
70             } 
71         } 
72         else//x<-->y 
73         { 
74             if(x==y) 
75             { 
76                 ans++; 
77                 continue; 
78             } 
79             if(flag) 
80             { 
81                 if(fa[b[0]]!=a[0]) 
82                     ans++; 
83             } 
84             else
85             { 
86                 for(j=0;j<=2;j++) 
87                     p[b[j]]=a[(j+2)%3]; 
88             } 
89         } 
90     } 
91     printf("%d\n",ans); 
92 } 
93 int main() 
94 { 
95     Pre(); 
96     Work(); 
97     return 0; 
98 } 

至此,此题完美解决。

转载于:https://www.cnblogs.com/CQBZOIer-zyy/archive/2013/03/18/2965366.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值