zoj 3500 island communication

Island Communication

Time Limit: 2 Seconds      Memory Limit: 65536 KB

Once upon a time, human have not invented boats and planes, bridges were the most important things in communication among islands. There is a large kingdom consists of N islands. One day, a terrible war broken out in this country. Due to the war, there might be several bridges being built or destroyed in each day. Tom, one of your best friends, is a business man. People always earn lots of money during the war, and certainly Tom doesn't want to lose this chance. But he doesn't know whether he can get to one island from another island, so he comes to you for help.

Input

There are multiple cases. The first line of each case consists of two integers N and M (1≤N≤500, 1≤M≤50000), indicates the number of islands and the number of operations. The indies of the island are from 1 to N. Then comes M lines of operations. There are three kinds of operations:

  1. I x y: means they build a bridge connects island x and island y
  2. D x y: means they destroy the bridge which connects island x and island y
  3. Q x y: Tom want to know whether he can get to island y from island x

Assume there are no bridges at the beginning, and each bridge will be built at most once(means when one bridge is destroyed, you can never build it any more)

Output

In the first line, you must output the case number. And for each query, you must output "YES" if you can get to island y from island x. otherwise output "NO".

Print a blank line between cases.

Sample Input

5 9
I 1 2
I 2 3
Q 1 3
I 1 3
I 2 4
I 4 5
D 1 2
D 2 3
Q 1 5

Sample Output

Case 1:
YES
NO

Author: YANG, Kete
Submit    Status


看别人的.

50000次操作, 所以普通做法会超时.

每个边最多删除一次, 插入一次, 可以在插入边的时候同时删除边, 同时只要保证连通性就行了, 当要加入边a, b时, 假设在加边前 a 和 b 之间只有一条路, 组成这条路的边在以后某个时刻会被删掉, 让我们删掉将最早被删除的边, 再加入ab边,  这样保证了连通性, 也保证了边数尽量少, 也符合前面的假设(ab间只有一条路). 其实每个连同分量是一棵树, 边保持在O(n), 那么对图的每次遍历相当于对树的遍历, 这样就有O(n*m)的复杂度.



#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <cstring>
#include <algorithm>
#include <vector>
#include <utility>

using namespace std;

#define NODES_MAX 510
#define INPUTS_MAX 50010
#define INF 100000000

vector <vector <int> > adj;
bool isEdge [NODES_MAX][NODES_MAX];

int deleteTime [NODES_MAX][NODES_MAX];

struct Input {
    char _op;
    int _a, _b;
    Input (char op, int a, int b): _op (op), _a (a), _b (b) {}
    Input (const Input &i): _op (i._op), _a (i._a), _b (i._b) {}
};

vector <Input> input;

void InitGraph (int n) {
    adj.clear();
    adj.resize (n);
    memset (isEdge, 0, sizeof (isEdge));
}

void NewEdge (int a, int b) {
    if (isEdge [a][b]) {
        return;
    }
    adj[a].push_back (b);
    adj[b].push_back (a);
    isEdge [a][b] = isEdge [b][a] = true;
#ifdef _DEBUG
    printf ("new edge (%d====%d)\n", a, b);
#endif
}

void DeleteEdge (int a, int b) {
    if (! isEdge [a][b]) {
        return;
    }
    int i = int (find (adj[a].begin(), adj[a].end(), b) - adj[a].begin());
    swap (adj[a][i], (int &) (adj[a].back()));
    adj[a].pop_back();

    i = int (find (adj[b].begin(), adj[b].end(), a) - adj[b].begin());
    swap (adj[b][i], (int &) (adj[b].back()));
    adj[b].pop_back();

    isEdge [a][b] = isEdge [b][a] = false;
#ifdef _DEBUG
    printf ("delete edge (%d====%d)\n", a, b);
#endif
}

bool DFS (int v, int dest, int father, int &ind) {
    if (v == dest) {
        return true;
    }
    // try every edge 'v' ====> 'a'
    for (int i=0; i<int(adj[v].size()); ++i) {
        int a = adj[v][i];
        if (a != father && DFS (a, dest, v, ind)) {
            ind = min (ind, deleteTime [v][a]);
            return true;
        }
    }
    return false;
}

int main () {
    int n, m;
    while (scanf ("%d%d", &n, &m) == 2) {
        InitGraph (n);
        input.clear();
        fill (deleteTime[0], deleteTime[NODES_MAX], INF);

        for (int i=0; i<m; ++i) {
            int a, b;
            char op[2];
            scanf ("%s%d%d", op, &a, &b);
            --a, --b;
            input.push_back (Input (*op, a, b));
            if (*op == 'D') {
                deleteTime [a][b] = deleteTime [b][a] = i;
            }
        }

        static int cs = 0;
        printf (cs ? "\n" : "");
        printf ("Case %d:\n", ++cs);

        for (int i=0; i<int(input.size()); ++i) {
            if (input[i]._op == 'D') {
                DeleteEdge (input[i]._a, input[i]._b);
            } else if (input[i]._op == 'Q') {
                int t = INF;
                printf (DFS (input[i]._a, input[i]._b, -1, t) ? "YES\n" : "NO\n");
            } else {
                int t = INF;
                if (! DFS (input[i]._a, input[i]._b, -1, t)) {
                    NewEdge (input[i]._a, input[i]._b);
                } else if (t < INF) {
                    DeleteEdge (input[t]._a, input[t]._b);
                    NewEdge (input[i]._a, input[i]._b);
                }
            }
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值