https://codeforces.com/contest/2002
D1 — DFS Checker (Easy Version) and D2 — DFS Checker (Hard Version)
解析:
找一种简单以维护的方法判断dfs程序的正确性:
根据树的性质容易知道:对于节点 u 和其子节点 v,id[u] 为节点 u 在dfs序中的位置,size[u] 为以u为根的子树的大小。不难发现 [ id[v],id[v]+size[v]-1 ] 包含于 [ id[u],id[u]+size[u]-1 ],因此可以通过维护这两类区间来判断dfs序的正确性。
首先需要一个set<int>son[i],表示以 i 为父节点的子节点的在dfs序中的位置,通过以下代码便可判断出dfs序的正确性。
int check(int x) {
return son[x].empty() ? 1 : (id[x] < *son[x].begin() &&
*--son[x].end() + siz[p[*--son[x].end()]] <= id[x] + siz[x]);
}
完整代码:
#include <iostream>
#include <string>
#include <cstring>
#include <cmath>
#include <ctime>
#include <algorithm>
#include <utility>
#include <stack>
#include <queue>
#include <vector>
#include <set>
#include <math.h>
#include <map>
#include <sstream>
#include <deque>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#include <stdio.h>
#include <tuple>
using namespace std;
/*
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
*/
typedef long long LL;
//#define int LL
#define ld long double
const LL INF = 0x3f3f3f3f3f3f3f3f;
typedef unsigned long long ULL;
typedef pair<long long, long long> PLL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
const int inf = 0x3f3f3f3f;
const LL Mod = 998244353;
const ld eps = 1e-12;
const int N = 3e5 + 10, M = 5e5 + 10;
int n, Q;
int fa[N], p[N], id[N], siz[N];
set<int>son[N];
int check(int x) {
return son[x].empty() ? 1 : (id[x] < *son[x].begin() && *--son[x].end() + siz[p[*--son[x].end()]] <= id[x] + siz[x]);
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T;
cin >> T;
while (T--) {
cin >> n >> Q;
for (int i = 1; i <= n; i++) {
siz[i] = 1;
son[i].clear();
}
for (int i = 2; i <= n; i++) {
cin >> fa[i];
}
for (int i = n; i > 1; i--) {
siz[fa[i]] += siz[i];
}
for (int i = 1; i <= n; i++) {
cin >> p[i];
son[fa[p[i]]].insert(i), id[p[i]] = i;
}
int cnt = 0;
for (int i = 1; i <= n; i++) {
cnt += check(i);
}
int i, j;
while (Q--) {
cin >> i >> j;
int x = p[i], y = p[j];
set<int>s;
s.insert(x), s.insert(y), s.insert(fa[x]), s.insert(fa[y]);
for (auto x : s)
if (x)cnt -= check(x);
son[fa[x]].erase(i), son[fa[y]].erase(j);
swap(p[i], p[j]), swap(id[x], id[y]);
son[fa[x]].insert(j), son[fa[y]].insert(i);
for (auto x : s)
if (x)cnt += check(x);
if (cnt == n) {
cout << "YES" << endl;
}
else {
cout << "NO" << endl;
}
}
}
return 0;
}
/*
3
3 3
1 1
1 2 3
2 3
3 2
1 3
7 4
1 1 2 2 3 3
1 2 3 4 5 6 7
3 5
2 5
3 7
4 6
5 4
1 1 3 4
2 3 4 5 1
5 1
4 5
3 4
2 3
*/
E. Cosmic Rays
解析:
问题要求对每个前缀给出答案,这暗示了一种增量解决方案。
为了将一个新对添加到当前前缀中,我们需要以某种方式处理新块与旧块的合并。因此,我们应使用某种结构来存储关于最后一个块随时间的信息。
具体地,我们使用栈来跟踪所有成为最后一个块的块。对于每个块,我们保留两个值:它的颜色 c 和它的寿命 l(块消失所需的时间)。
插入一个新块时,我们将弹出所有会被当前块遮蔽的块(即寿命短于当前块的块),并合并具有相同颜色的块。当合并两个长度分别为 x 和 z 的块,且它们之间块的最大寿命为 y 时,应满足 y≤min(x,z),新块将具有 x+z−y 的寿命。
有关更多详细信息,请参考解决方案代码。
还存在使用有序集合或堆的 O(nlogn)解决方案。
时间复杂度:O(n)
#include <iostream>
#include <string>
#include <cstring>
#include <cmath>
#include <ctime>
#include <algorithm>
#include <utility>
#include <stack>
#include <queue>
#include <vector>
#include <set>
#include <math.h>
#include <map>
#include <sstream>
#include <deque>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#include <stdio.h>
#include <tuple>
using namespace std;
/*
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
*/
typedef long long LL;
#define int LL
#define ld long double
const LL INF = 0x3f3f3f3f3f3f3f3f;
typedef unsigned long long ULL;
typedef pair<long long, long long> PLL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
const int inf = 0x3f3f3f3f;
const LL Mod = 998244353;
const ld eps = 1e-12;
const int N = 3e5 + 10, M = 5e5 + 10;
int n;
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T;
cin >> T;
while (T--) {
cin >> n;
vector<PII>stk;
int ans = 0;
vector<int>out;
for (int i = 1; i <= n; i++) {
int a, b;
cin >> a >> b;
int len = 0;
while (!stk.empty() && (a > 0 || stk.back().second == b)) {
if (stk.back().second == b) {
len += stk.back().first;
stk.pop_back();
}
else {
int t = min(a, stk.back().first);
len += t;
a -= t;
stk.back().first -= t;
if (stk.back().first == 0) {
stk.pop_back();
}
}
}
len += a;
ans += a;
stk.push_back({ len,b });
//cout << "____________" << len << " " << b << endl;
out.push_back(ans);
}
for (int x : out) {
cout << x << " ";
}
cout << endl;
}
return 0;
}