[Luogu P2341] [HAOI2006]受欢迎的牛
      
      
    
   
  
  
    题面
传送门:洛谷
Solution
前排提示,本蒟蒻做法既奇葩又麻烦 我们先可以把题目转换一下。 可以把一头牛喜欢另外一头牛理解为另外一头牛被一头牛喜欢。 我们把被喜欢的关系建边,即B被A喜欢,从B向A连一条有向边。 显然,一个点若能到达其他所有节点,它就是题目中的明星牛。 接下来,我们可以考虑一个类似于DP的做法。 即一个点能访问到的点,等同于它的儿子们访问的到的点加上它自己。 显然,这种特性要在DAG(有向无环图)上才能方便的使用。 所以说,我们第一步要对题目做的是缩点。 缩完点之后,我们就可以进行图上DP了。 我们可以用一个01数组$f[i][j]$表示i能具体能到达的点为j(用010101数列表示)。 显然 f[i] = f[k] (或运算)(k为i直接相连的点) 答案为f[i][j] j=11111111… 的点 当然,这样做有一个问题。 点的最大数目为n,我们这样做是$O(n^2)$的,在最坏条件(没有一个点能缩在一起)的情况下,会T。 我们这时候就得请出bitset。 bitset的食用方法(借用胡小兔dalao的博客) 使用bitset后,我们计算一个点能到达其他的点的复杂度一下子降为了$O(n/32)$ 总复杂度为$O(n^2/32)$ 然后就可以过啦。
Code
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 
 | 
 
 #include<iostream>
 #include<cstdio>
 #include<vector>
 #include<stack>
 #include<bitset>
 using namespace std;
 long long read()
 {
 long long x=0,f=1; char c=getchar();
 while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
 while(isdigit(c)){x=x*10+c-'0';c=getchar();}
 return x*f;
 }
 const int  N=10000+100;
 vector <int> e[N],e2[N];
 int n,m,belong[N],nd_tot,dfn[N],mcount,low[N],cnt[N];
 bool InStack[N];
 stack <int> s;
 bitset <N> arrival[N];
 void Tarjan(int now)
 {
 InStack[now]=true;
 s.push(now);
 dfn[now]=low[now]=++mcount;
 for(int i=0;i<int(e[now].size());i++)
 if(dfn[e[now][i]]==0)
 {
 Tarjan(e[now][i]);
 low[now]=min(low[now],low[e[now][i]]);
 }
 else if(InStack[e[now][i]]==true)
 low[now]=min(low[now],low[e[now][i]]);
 if(low[now]==dfn[now])
 {
 nd_tot++;
 while(s.empty()==false)
 {
 int temp=s.top();
 s.pop();
 InStack[temp]=false;
 belong[temp]=nd_tot;
 cnt[nd_tot]++;
 if(temp==now) break;
 }
 arrival[nd_tot][nd_tot]=true;
 }
 }
 bool vis[N];
 int ans=0;
 void dfs(int now)
 {
 vis[now]=true;
 for(int i=0;i<int(e2[now].size());i++)
 {
 if(vis[e2[now][i]]==false)
 dfs(e2[now][i]);
 arrival[now]=arrival[e2[now][i]];
 }
 if(int(arrival[now].count())==nd_tot)
 ans+=cnt[now];
 }
 int main()
 {
 n=read(),m=read();
 for(int i=1;i<=n;i++)
 e2[i].reserve(4),
 e[i].reserve(4);
 for(int i=1;i<=m;i++)
 {
 int s=read(),t=read();
 e[t].push_back(s);
 }
 
 for(int i=1;i<=n;i++)
 if(dfn[i]==0)
 Tarjan(i);
 for(int i=1;i<=n;i++)
 for(int j=0;j<int(e[i].size());j++)
 if(belong[i]!=belong[e[i][j]])
 e2[belong[i]].push_back(belong[e[i][j]]);
 for(int i=1;i<=nd_tot;i++)
 if(vis[i]==false)
 dfs(i);
 
 printf("%d",ans);
 return 0;
 }
 
 
 
 |