[JSOI2015]最小表示

之前连bitset都不会写......为了写这道题去学习了一下bitset的用法

首先要得到一个很显然的结论,就是如果\(x\)\(y\)之间的边可以被删去,那么\(x\)一定可以通过别的路径走到\(y\),然后在这里我们就需要用bitset来维护点与点之间的连通性

因为这是一个有向无环图,所以我们直接拓扑排序,然后从出度为零的点逆序入队,将每一个结点的子节点按照到出度为零的点的距离由大到小排序,可以保证最优,然后判一下\(bit[x][son]\)是不是1,如果是1就说明这条边是可以删掉的

#include<bits/stdc++.h>
using namespace std;
int n,m,x,y,r[30003],ru[30003],p,hd,st[30003],ans;
queue<int>q;
vector<int>l[30003];
bitset<30003>bit[30003];
int cmp(int nx,int ny)
{
	return r[nx]>r[ny];
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		l[x].push_back(y),ru[y]++;
	}
	for(int i=1;i<=n;i++)
		if(ru[i]==0)
			q.push(i);
	while(!q.empty())
	{
		p=q.front(),q.pop(),hd++,st[hd]=p;
		for(int j=0;j<l[p].size();j++)
		{
			ru[l[p][j]]--;
			if(ru[l[p][j]]==0)
				q.push(l[p][j]);
		}		
	}
	for(int i=n;i>=1;i--)
	{
		x=st[i],bit[x][x]=1;
		sort(l[x].begin(),l[x].end(),cmp);
		for(int j=0;j<l[x].size();j++)
		{
			r[x]=max(r[l[x][j]]+1,r[x]);
			if(bit[x][l[x][j]]==1)
				ans++;
			else
				bit[x]|=bit[l[x][j]];
		}
	}
	cout<<ans;
	return 0;
}

posted @ 2020-02-05 18:49  dz_ice  阅读(221)  评论(0编辑  收藏  举报