• [BZOJ4484][JSOI2015]最小表示(拓扑排序+bitset)


    有一个结论:对于边<u,v>,若这是u到v的唯一路径,则这条边显然不可被删去,否则必然可以被删去。

    因为若u到v还有其它路径,则必然是从u到某个点x再到v,由于最终答案中连通性不变,也就是最终答案中仍然可以走到x后再走到v,于是可以删去这条边。

    于是大致算法就出来了:按拓扑序从后往前做,每次将这个点的所有出边到达的点按拓扑序从小到大处理,若某个出点已经可以被到达了则删边。

    bitset维护连通性,$O(nm/32)$

     1 #include<cstdio>
     2 #include<bitset>
     3 #include<algorithm>
     4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     5 #define For(i,x) for (int i=h[x],k; i; i=nxt[i])
     6 using namespace std;
     7 
     8 const int N=100010;
     9 int n,m,cnt,x,y,p[N],id[N],d[N],q[N],v[N],t,ans,h[N],to[N],nxt[N];
    10 bitset<30010> a[30010],b;
    11 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
    12 
    13 void Top(){
    14     int st=0,ed=0;
    15     rep(i,1,n) if (!d[i]) q[++ed]=i,id[i]=ed;
    16     while (st<ed){
    17         int x=q[++st];
    18         For(i,x) if (!--d[k=to[i]]) q[++ed]=to[i],id[to[i]]=ed;
    19     }
    20 }
    21 
    22 bool cmp(const int &a,const int &b){ return id[a]<id[b]; }
    23 
    24 int main(){
    25     scanf("%d%d",&n,&m);
    26     rep(i,1,m) scanf("%d%d",&x,&y),add(x,y),d[y]++;
    27     Top();
    28     for (int i=n; i; i--){
    29         int x=q[i],tot=0; a[x][x]=1;
    30         For(j,x) v[++tot]=k=to[j];
    31         sort(v+1,v+tot+1,cmp);
    32         rep(j,1,tot) if (a[x][v[j]]) ans++; else a[x]|=a[v[j]];
    33     }
    34     printf("%d
    ",ans);
    35     return 0;
    36 }
  • 相关阅读:
    工程思维
    小骆驼 第三章 列表与数组
    小骆驼 第二章 标量数据
    小骆驼 第二章 标量数据
    小骆驼 第二章 标量数据
    split和join合写
    Competition and Predation
    What is the difference between Θ(n) and O(n)?
    数学基础之概率统计
    enumerate()函数
  • 原文地址:https://www.cnblogs.com/HocRiser/p/10055027.html
Copyright © 2020-2023  润新知