这题有一个大坑:同一节点,同一时间,可能产生多个块。即,存在 和 ,其中 ,这样的输入存在。( )
题目中没有找到对这一点的说明,示例输入输出也没有体现。当然,题目也没有明示这样是不可能的。如果理解错误,将cre
设定为map<int, unordered_map<int, int>>
的话,就只有80分。
#include <bits/stdc++.h>
using namespace std;
int n, m, t, k;
vector<vector<int>> G; // 邻接表方式存图
map<int, unordered_map<int, vector<int>>> rec; // 收到的链,按‘时间-节点-链’组织
vector<vector<int>> links; // 当前各节点的主链
map<int, unordered_map<int, vector<int>>> cre; // 创建的新块,按‘时间-节点-块号链’组织。同一时刻,同一节点,可以产生多个块
vector<int> input() {
string line;
getline(cin, line);
istringstream iss(line);
vector<int> res;
int x = 0;
while (iss >> x) res.push_back(x);
return res;
}
// 节点idx在时刻time接收到链vec的处理过程
void update(int time, int idx, const vector<int>& vec) {
auto& cur = links[idx];
if (cur.size() < vec.size() || cur.size() == vec.size() && cur.back() > vec.back()) {
cur = vec;
// links[idx]更新了,将新链推送给邻居
for (int nei: G[idx]) {
auto& temp = rec[time + t][nei];
// 邻居在同一时刻可能收到多个链,只需保留最长且最后一个块号最小的链
if (temp.size() < cur.size() || temp.size() == cur.size() && temp.back() > cur.back()) {
temp = cur;
}
}
}
}
// 按时间顺序处理积攒的rec和cre操作,直至时刻T
void proceedUntil(int T) {
auto rec_p = rec.begin(); // rec_p将始终指向rec的第一个元素,或rec.end(),如果rec为空
auto cre_p = cre.begin(); // cre_p将始终指向cre的第一个元素,或cre.end(),如果cre为空
while (rec_p != rec.end() || cre_p != cre.end()) {
if (cre_p == cre.end() || rec_p != rec.end() && rec_p->first <= cre_p->first) { // 先处理接收到的链
if (rec_p->first > T) break;
for (const auto& ele: rec_p->second) {
update(rec_p->first, ele.first, ele.second);
}
rec_p = rec.erase(rec_p);
} else { // 再处理新建操作,两者都划归到update上
if (cre_p->first > T) break;
for (const auto& ele: cre_p->second) {
auto temp = links[ele.first];
temp.insert(temp.end(), ele.second.begin(), ele.second.end());
update(cre_p->first, ele.first, temp);
}
cre_p = cre.erase(cre_p);
rec_p = rec.begin(); // 调用update之后,rec可能被修改,rec_p可能因此而失效
}
}
}
// 加快cin和cout的速度
static const int _ = []() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
return 0;
}();
int main() {
cin >> n >> m;
G.resize(n + 1);
links.resize(n + 1, {0});
for (int i = 0; i < m; ++i) {
int u, v;
cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
}
cin >> t >> k;
cin.get(); // 去掉输入流里一个换行符
while (k--) {
vector<int> op = input();
if (op.size() == 3) { // 创建块,将操作缓存起来,不立刻处理
cre[op[1]][op[0]].push_back(op[2]);
} else { // 等查询主链时,才依次处理完时刻op[1]及其之前的操作
proceedUntil(op[1]);
cout << links[op[0]].size();
for (int x: links[op[0]]) cout << " " << x; cout << endl;
}
}
return 0;
}
附:
1.in
5 10
1 2
1 3
1 4
1 5
2 3
2 4
2 5
3 4
3 5
4 5
1 27
1 1 1
2 1 2
3 1 3
4 1 4
5 1 5
1 1
2 1
3 1
4 1
5 1
1 2
2 2
3 2
4 2
5 2
1 10 10
2 11 9
1 11
2 11
3 11
4 11
5 11
1 12
2 12
3 12
4 12
5 12
1.out
2 0 1
2 0 2
2 0 3
2 0 4
2 0 5
2 0 1
2 0 1
2 0 1
2 0 1
2 0 1
3 0 1 10
4 0 1 10 9
3 0 1 10
3 0 1 10
3 0 1 10
4 0 1 10 9
4 0 1 10 9
4 0 1 10 9
4 0 1 10 9
4 0 1 10 9
2.in
15 13
1 2
2 3
3 4
4 5
1 6
6 7
7 8
8 9
1 10
10 11
11 12
12 13
14 15
6 28
1 1 1
1 2 2
1 6
2 7
13 7
9 7
5 7
3 14
8 14
5 14
11 14
9 25
5 25
13 25
9 28 3
5 29 4
13 29 5
1 53
2 59 6
2 59
1 1000
3 1000
8 1000
9 1000
10 1000
13 1000
14 1000
15 1000
2.out
3 0 1 2
2 0 1
1 0
1 0
1 0
3 0 1 2
1 0
1 0
3 0 1 2
2 0 1
2 0 1
2 0 1
4 0 1 2 3
5 0 1 2 3 6
5 0 1 2 3 6
5 0 1 2 3 6
5 0 1 2 3 6
5 0 1 2 3 6
5 0 1 2 3 6
5 0 1 2 3 6
1 0
1 0