1. 程式人生 > >2017四川省賽D題《Dynamic Graph》

2017四川省賽D題《Dynamic Graph》

void 一個 log 白色 () eset using 範圍 題意

題意:給出一個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\n", 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\n", ans);
        }
    }
    return 0;
}

  

2017四川省賽D題《Dynamic Graph》