[JSOI2015]最小表示

4484: [Jsoi2015]最小表示

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 327  Solved: 163
[Submit][Status][Discuss]

Description

【故事背景】
还记得去年JYY所研究的强连通分量的问题吗?去年的题目里,JYY研究了对于有向图的“加边”问题。对于图论有着强烈兴趣的JYY,今年又琢磨起了“删边”的问题。
【问题描述】
对于一个N个点(每个点从1到N编号),M条边的有向图,JYY发现,如果从图中删去一些边,那么原图的连通性会发生改变;而也有一些边,删去之后图的连通性并不会发生改变。
JYY想知道,如果想要使得原图任意两点的连通性保持不变,我们最多能删掉多少条边呢?
为了简化一下大家的工作量,这次JYY保证他给定的有向图一定是一个有向无环图(JYY:大家经过去年的问题,都知道对于给任意有向图的问题,最后都能转化为有向无环图上的问题,所以今年JYY就干脆简化一下大家的工作)。

Input

输入一行包含两个正整数N和M。
接下来M行,每行包含两个1到N之间的正整数x_i和y_i,表示图中存在一条从x_i到y_i的有向边。
输入数据保证,任意两点间只会有至多一条边存在。
N<=30,000,M<=100,000

Output

输出一行包含一个整数,表示JYY最多可以删掉的边数。

Sample Input

5 6
1 2
2 3
3 5
4 5
1 5
1 3

Sample Output

2

HINT

 

Source

 
 
bitset压位经典题233333
拓扑排序之后逆序更新,bitset维护联通性。
 
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=30005;
const int maxm=100005;
bitset<maxn> NUM[maxn];
int to[maxm],ne[maxm];
int n,m,hd[maxn],ans=0;
int id[maxn],q[maxn],l,r;
int topsort[maxn],now=0,S;
struct node{
	int pos,val;
	bool operator <(const node &u)const{
		return val<u.val;
	}
}a[maxn];

inline void solve(){
	l=1; int x; node y;
	for(int i=1;i<=n;i++) if(!id[i]) q[++r]=i;
	while(l<=r){
		x=q[l++],topsort[x]=++now;
		for(int i=hd[x];i;i=ne[i])
		    if(!(--id[to[i]])) q[++r]=to[i];
	}
	
	for(int i=r;i;i--){
		x=q[i],NUM[x][x]=1,S=0;
		for(int j=hd[x];j;j=ne[j]) a[++S]=(node){to[j],topsort[to[j]]};
		sort(a+1,a+S+1);
		for(int j=1;j<=S;j++){
			y=a[j];
			if(NUM[x][y.pos]) ans++;
			else NUM[x]|=NUM[y.pos];
		}
	}
}

int main(){
	int uu,vv;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		scanf("%d%d",&uu,&vv),id[vv]++;
		to[i]=vv,ne[i]=hd[uu],hd[uu]=i;
	}
	
	solve();
	
	printf("%d
",ans);
	return 0;
}

  

原文地址:https://www.cnblogs.com/JYYHH/p/8546431.html