Loading

NOIP 模拟 $17\; \rm 世界线$

题解 \(by\;zj\varphi\)

此题经简单观察可发现,一个点的贡献就是这个点所能到的点减去它的出度

那么我们就可以暴力搜索,但是显然会超时,所以我们可以使用一个黑科技 \(\rm bitset\),这个东西可以整体位运算

我们设 \(bit_{i,j}\) 表示 \(i\) 能到 \(j\),转移时直接 \(bit_{i}|=bit_{v}\)

但是这样会爆空间,正解是分块,以时间来换取空间,但这样有些麻烦,我们发现,当一个点被访问次数已经等于它的入度了,这个点就没用了

所以我们直接将没用的 \(\rm bitset\) 回收即可,最后别忘了处理根。

Code
#include<bits/stdc++.h>
#define ri register signed
#define p(i) ++i
using namespace std;
namespace IO{
    char buf[1<<21],*p1=buf,*p2=buf;
    #define gc() p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++
    template<typename T>inline void read(T &x) {
        ri f=1;x=0;register char ch=gc();
        while(ch<'0'||ch>'9') {if (ch=='-') f=0;ch=gc();}
        while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
        x=f?x:-x;
    }
}
using IO::read;
namespace nanfeng{
    #define FI FILE *IN
    #define FO FILE *OUT
    template<typename T>inline T cmax(T x,T y) {return x>y?x:y;}
    template<typename T>inline T cmin(T x,T y) {return x>y?y:x;}
    typedef long long ll;
    static const int N=6e4+1,M=1e5+7;
    unsigned first[N],vis[N],out[N],st[N],be[N],in[N],tot,tp,n;
    int m,t=1;
    ll ans;
    bitset<N> bit[N];
    struct edge{unsigned v,nxt;}e[M];
    inline void add(unsigned u,unsigned v) {e[t].v=v,e[t].nxt=first[u],first[u]=t++;}
    inline int New() {return tp?st[tp--]:tot++;}
    inline void Throw(int x) {
        ans+=bit[be[x]].count()-1-out[x];
        bit[st[p(tp)]=be[x]].reset();
    }
    void dfs(int x) {
        vis[x]=1;
        if (!be[x]) be[x]=New();
        bit[be[x]][x]=1;
        for (ri i(first[x]),v;i;i=e[i].nxt) {
            --in[v=e[i].v];
            if (vis[v]) {
                bit[be[x]]|=bit[be[v]];
                if (!in[v]) Throw(v);
                continue;
            } else dfs(v);
            bit[be[x]]|=bit[be[v]];
            if (!in[v]) Throw(v);
        }
    }
    inline int main() {
        // FI=freopen("nanfeng.in","r",stdin);
        // FO=freopen("nanfeng.out","w",stdout);
        read(n),read(m);
        for (ri i(1),u,v;i<=m;p(i)) read(u),read(v),add(u,v),p(out[u]),p(in[v]);
        for (ri i(1);i<=n;p(i)) {
            if (!vis[i]) {
                dfs(i);
                if (!in[i]) Throw(i);
            }
        }
        printf("%lld\n",ans);
        return 0;
    }  
}
int main() {return nanfeng::main();} 
posted @ 2021-07-18 14:27  ナンカエデ  阅读(41)  评论(0编辑  收藏  举报