4484: [Jsoi2015]最小表示
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 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
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; }