Works Applications2016校園招聘 — Travel Information Center

Problem


Aps Island has many cities. In the summer, many travellers will come to the island and attend festive events in different cities. The festive events in Aps Island are crazy. Once it starts, it will never end. In the following sentences, the cities which have festive events are called festive cities.

At the beginning, only city No. 1 is festive city. If a new city becomes festive city, the government will tell the information center about this news.

Everyday, the information center will receive many inquiries from travellers from different cities of this land. They want to know the closest festive city, and calculate the distance (If current city has festive event, the distance is 0).

Due to the growing number of the travellers, the information center is overloaded. The government wants to fix the problem by developing a system to handle the inquiries automatically.

As a fact, cities in Aps Island are connected with highways(bidirectional, length of every highway is 1). Any two cities are connected directly or indirectly, and there is ONLY one path between any 2 cities.

Input

There are two integers in the first line, n (2 ≤ n ≤ 10^5) and m ( 1 ≤ m ≤ 10^5), n is the number of cities in the Aps Island and m is the number of queries. The coming n-1 lines are the highways which connect two cities. In the line, there are two integers ai and bi (1 ≤ ai, bi ≤ n, ai ≠ bi), representing two cities. Each line means the highway connecting the two cities.

Next m lines are inquiries from travellers or news from government. Each line has two integers qi and ci (1 ≤ qi ≤ 2, 1 ≤ ci ≤ n). If qi = 1, the government announces a new festive city ci. If qi = 2, you have to find and print the shortest distance from the city ci to the closest festive city.

Output

Results from each (qi = 2) Questions. Print every result with a new line.

Sample Test


input

5 5
1 2
1 3
3 4
3 5
2 5
2 3
1 3
2 3
2 4

output

2
1
0
1

Solution 1


思路

用dis[i]表示節點i離最近標記節點的距離,每次標記新的節點時遞歸更新所有節點狀態,有剪枝。最後在查詢的時候直接輸出dis[x]即可。

代碼

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <map>
#include <algorithm>
using namespace std;

struct Node {
    vector<int> eds;
};
Node node[100001];
int dis[100001];    //dis[i]表示結點i離最近標記結點的距離
int m, n;

//更新以x爲根節點,p爲x的父節點的子樹的狀態,有剪枝
void dfs(int x, int p) {
    vector<int> vecs = node[x].eds;
    for (int i = 0; i < vecs.size(); ++i) {
        if (vecs[i] == p)
            continue;
        if (dis[vecs[i]] == -1 || dis[vecs[i]] > dis[x] + 1) {
            dis[vecs[i]] = dis[x] + 1;
            dfs(vecs[i], x);
        }
    }
}

int main() {
    memset(dis, -1, sizeof(dis));

    scanf("%d%d", &m, &n);
    int a, b;
    for (int i = 1; i < m; ++i) {
        scanf("%d%d", &a, &b);
        node[a].eds.push_back(b);
        node[b].eds.push_back(a);
    }
    dis[1] = 0;
    dfs(1, 0);
    for (int i = 0; i < n; ++i) {
        scanf("%d%d", &a, &b);
        if (a == 1) {
            dis[b] = 0;
            dfs(b, 0);
        }
        else {
            printf("%d\n", dis[b]);
        }
    }
    return 0;
}

Solution 2


思路

solution 1中,如果當所有節點連成一條“直線”的時候,更新節點狀態的時候不知道會不會爆棧。現在還有另外一種方法就是,我們在標記新的節點時只是單純記錄下標記節點即可,在每次查詢的時候再利用廣搜找到最近標記節點。

代碼

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <map>
#include <queue>
#include <algorithm>
using namespace std;

struct Node {
    bool flag;    //記錄該節點是否被標記
    vector<int> eds;

    Node() {
        flag = false;
    }
};
Node node[100001];
int m, n;

struct State {
    int par;    //父節點
    int no;
    int dis;
};

int bfs(int x) {
    queue<State> que;
    State sta;
    sta.par = 0;
    sta.no = x;
    sta.dis = 0;
    que.push(sta);
    while (!que.empty()) {
        State cur = que.front();
        que.pop();
        if (node[cur.no].flag)
            return cur.dis;
        vector<int> vecs = node[cur.no].eds;
        for (int i = 0; i < vecs.size(); ++i) {
            if (vecs[i] == cur.par)
                continue;
            State ns;
            ns.par = cur.no;
            ns.no = vecs[i];
            ns.dis = cur.dis + 1;
            que.push(ns);
        }
    }
}

int main() {
    scanf("%d%d", &m, &n);
    int a, b;
    for (int i = 1; i < m; ++i) {
        scanf("%d%d", &a, &b);
        node[a].eds.push_back(b);
        node[b].eds.push_back(a);
    }

    node[1].flag = true;
    for (int i = 0; i < n; ++i) {
        scanf("%d%d", &a, &b);
        if (a == 1) {
            node[b].flag = true;
        }
        else {
            int dis = bfs(b);
            printf("%d\n", dis);
        }
    }
    return 0;
}

目前能想到的只有這兩種方法了,雖然都能AC,但總感覺還有更優化的方法。

發佈了88 篇原創文章 · 獲贊 91 · 訪問量 108萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章