• 2017四川省赛D题《Dynamic Graph》


    题意:给出一个n个点m条边的有向无环图(DAG),初始的时候所有的点都为白色。然后有Q次操作,每次操作要把一个点的颜色改变,白色<->黑色,对于每次操作,输出满足下列点对<u,v>,u,v都为白色且可以相互到达的个数。

    数据范围:

    DAG上的问题,首先最暴力的方法就是,对于每一次更改都进行一遍dfs,B[u][v],表示U点可以到达v点,然后对于U的父亲结点来说,暴力合并,复杂度约为n^4,这样显然会爆炸。解法是每次用BITSET优化,因为B[u][v]的状态非零即一。

    代码如下:

    #include<bits/stdc++.h>
    typedef long long LL;
    using namespace std;
    const int maxn = 350;
    int N, M, Q;
    struct Edge
    {
        int to, next;
        Edge(int to = 0, int next = 0): to(to), next(next) {}
    } E[maxn * maxn];
    int head[maxn], tot;
    void initedge()
    {
        memset(head, -1, sizeof(head));
        tot = 0;
    }
    void addedge(int u, int v)
    {
        E[tot] = Edge(v, head[u]);
        head[u] = tot++;
    }
    bitset<maxn>BT[maxn];
    int vis[maxn], cul[maxn];
    void init()
    {
        for(int i = 0; i <= N; i++)
        {
            BT[i].reset();
            vis[i] = cul[i] = 0;
        }
    }
    void DFS(int u)
    {
        BT[u].reset();
        BT[u][u] = 1;
        vis[u] = 1;
        if(cul[u]) return ;
        for(int k = head[u]; ~k; k = E[k].next)
        {
            int v = E[k].to;
            if(!vis[v]) DFS(v);
            if(!cul[v]) BT[u] |= BT[v];
        }
    }
    int main ()
    {
        while(~scanf("%d %d %d", &N, &M, &Q))
        {
            init();
            initedge();
            for(int i = 1; i <= M; i++)
            {
                int u, v;
                scanf("%d %d", &u, &v);
                addedge(u, v);
            }
            for(int i = 1; i <= Q; i++)
            {
                int u, ans = 0;
                scanf("%d", &u);
                cul[u] ^= 1;
                for(int i = 1; i <= N; i++) vis[i] = 0;
                for(int i = 1; i <= N; i++)
                {
                    if(!vis[i]) DFS(i);
                    ans += BT[i].count() - 1;
                }
                printf("%d
    ", ans);
            }
        }
        return 0;
    }

    另外还有一种方法:

    维护F[u][v],表示u->v的路径条数,然后对于每次操作更新F[u][v]-+=F[u][x]*F[x][v],然后判断F[u][v]是否>0即可,这样做是对的,但是F[u][v]可能非常大,要用unsigned long long ,虽然unsigned long long 存不下,但是他有自动取模的功能,即使是这样也有可能出现F[u][v]之间有路径,但是取模后为0的情况,但是这个概率是很小的,unsigned long long 已经很大了,取模后出现零的情况应该不会被卡。unsigned int 也可以过。

    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    typedef unsigned long long LL;
    const int maxn = 350;
    LL dp[maxn][maxn], vis[maxn];
    int N, M, Q;
    void init()
    {
        for(int i = 1; i <= N; i++)
        {
            vis[i] = 0;
            for(int j = 1; j <= N; j++)
                dp[i][j] = 0;
        }
    }
    int main ()
    {
        while(~scanf("%d %d %d", &N, &M, &Q))
        {
            init();
            for(int i = 1; i <= M; i++)
            {
                int u, v;
                scanf("%d %d", &u, &v);
                dp[u][v]++;
            }
            for(int k = 1; k <= N; k++ )
                for(int st = 1; st < k; st++)
                    for(int ed = k + 1; ed <= N; ed++)
                        dp[st][ed] += dp[st][k] * dp[k][ed];
            for(int i = 1; i <= Q; i++)
            {
                int u;
                scanf("%d", &u);
                if(vis[u] == 0)
                {
                    vis[u] = 1;
                    for(int st = 1; st < u; st++)
                        for(int ed = u + 1; ed <= N; ed++)
                            dp[st][ed] -= dp[st][u] * dp[u][ed];
                }
                else
                {
                    vis[u] = 0;
                    for(int st = 1; st < u; st++)
                        for(int ed = u + 1; ed <= N; ed++)
                            dp[st][ed] += dp[st][u] * dp[u][ed];
                }
                int ans = 0;
                for(int st = 1; st <= N; st++)
                {
                    if(vis[st]) continue;
                    for(int ed = st + 1; ed <= N; ed++)
                    {
                        if(vis[ed]) continue;
                        if(dp[st][ed] > 0) ans++;
                    }
                }
                printf("%d
    ", ans);
            }
        }
        return 0;
    }
    

      

    想的太多,做的太少。
  • 相关阅读:
    第二阶段冲刺第二天
    第二阶段冲刺第一天
    学习进度表_十四周
    购买图书
    学习进度表_十三周
    寻找水王续
    学习进度表_十二周
    《梦断代码》读后笔记_4
    找水王
    学习进度表_十一周
  • 原文地址:https://www.cnblogs.com/pealicx/p/6994651.html
Copyright © 2020-2023  润新知