L3-032 关于深度优先搜索和逆序对的题应该不会很难吧这件事

题目链接

L3-032 关于深度优先搜索和逆序对的题应该不会很难吧这件事 - 团体程序设计天梯赛

题意

给定一棵 \(n\) 个节点的树,其中节点 \(r\) 为根。求该树所有可能的 DFS 序中逆序对数量之和。

思路

一开始分了两类,第一类为它的所有孩子,第二类为它父亲的除了它及它的孩子的所有孩子。所以少考虑了一些情况,写到最后样例没过才发现问题。第二类应为它的祖先的……

重新进行分类,不妨设它为 \(u\),第一类为 \(u\) 所有祖先,这一类贡献不会因为 DFS 改变而变。第二类为除了其祖先,子孙和 \(u\) 的所有结点,这一类会改变。

对于第二类结点,不妨设其中一个为 \(v\),对所有可能的 DFS序,有 \(\frac{1}{2}\) 的概率 \(u\)\(v\) 前面,\(\frac{1}{2}\) 的概率 \(u\)\(v\) 后面。\(u\) 与它的所有第二类结点都可能产生贡献,共计为 \[ \text{第二类结点数}\times\text{DFS 数量}\times\frac{1}{2}\times\frac{1}{2} \] 一个 \(\frac{1}{2}\) 为位置概率,另一个为一对 \((u,v)\) 其贡献会计算两次。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include<bits/stdc++.h>
// #define int long long
#define endl '\n'
#define debug(x) cout << #x << " = " << x << endl
#define debug2(x,y) cout << #x << " = " << x << " " << #y << " = "<< y << endl
#define lowbit(i) ((i) & (-i))
using namespace std;

typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int mod = 1e9 + 7;
const int maxn = 3e5 + 10;

vector<int> e[maxn];
int c[maxn], n, dep[maxn], son[maxn], fac[maxn];
LL base = 1, ans = 0;

LL qpow(LL b, LL p, int k) {
b %= k;
LL ans = 1;
for(; p; p >>= 1, b = b * b % k)
if(p & 1) ans = ans * b % k;
return ans;
}

void add(int x, int val) {
for(; x <= n; x += lowbit(x)) c[x] += val;
}

int sum(int x) {
int res = 0;
for(; x; x -= lowbit(x)) res += c[x];
return res;
}

void dfs(int u, int fa) {
dep[u] = dep[fa] + 1;
ans = (ans + dep[u] - 1 - sum(u)) % mod;
add(u, 1);
int cnt = 0;
for(auto v : e[u])
if(v != fa) {
cnt++;
dfs(v, u);
son[u] += son[v] + 1;
}
if(cnt) base = base * fac[cnt] % mod;
add(u, -1);
}

void solve() {
int r;
cin >> n >> r;
fac[0] = 1;
for(int i = 1; i <= n; i++)
fac[i] = (LL)fac[i - 1] * i % mod;
for(int i = 1; i < n; i++) {
int u, v;
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
}
dfs(r, 0);
ans = ans * base % mod;
int inv2 = qpow(2, mod - 2, mod);
for(int i = 1; i <= n; i++) {
ans = (ans + (n - dep[i] - son[i]) * base % mod * inv2 % mod * inv2 % mod) % mod;
}
cout << ans << endl;
}

// #define sunset
signed main() {
cin.tie(nullptr)->sync_with_stdio(false);

#ifdef sunset
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif

int T = 1;
// cin >> T;
while(T--) {
solve();
}
return 0;
}