传送门
idea:
参考自“我是小蜗蜗”
namo,除了remake,能不能像两位老师一样强啊
考虑单独的一个dfs序,存在父子关系的点对是否逆序数已确定,不存在父子关系的点对是否逆序数的概率各占 1 2 \frac{1}{2} 21
统计dfs序个数,考虑维护一个子树的dfs序数,当前节点的dfs序数等于( ∏ \prod ∏以其子节点为根的子树的dfs序数) × \times ×(子节点的排列数)
code:
f[] 为以u为子树的dfs序方案数,cntRev为在一个dfs序中确定的逆序对数量,cntNum为在一个dfs序中确定不是逆序对的数量,num为没有父子关系的点对数量
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
const ll N = 3e5 + 10;
vector<ll> g[N];
ll tree[N];
ll n, rt;
ll qpow(ll x, ll n) {
ll res = 1;
while (n) {
if (n & 1) res = res * x % mod;
x = x * x % mod;
n >>= 1;
}
return res;
}
ll lowbit(ll x) {
return x & (-x);
}
void add(ll p, ll x) {
while (p <= n) {
tree[p] = (tree[p] + x) % mod;
p += lowbit(p);
}
}
ll query(ll p) {
ll res = 0;
while (p) {
res = (res + tree[p]) % mod;
p -= lowbit(p);
}
return res;
}
ll cntRev = 0, cntNum = 0;
ll f[N];
ll fac[N];
void dfs(ll x, ll p) {
f[x] = 1;
for (auto to : g[x]) {
if (to == p) continue;
cntRev = (cntRev + query(n) - query(to) + mod) % mod;
cntNum = (cntNum + query(to)) % mod;
add(to, 1);
dfs(to, x);
f[x] = f[x] * f[to] % mod;
add(to, -1);
}
ll num = (x == rt ? g[x].size() : g[x].size() - 1);
f[x] = f[x] * fac[num] % mod;
}
signed main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
fac[0] = 1;
for (ll i = 1; i < N; ++i) fac[i] = fac[i - 1] * i % mod;
cin >> n >> rt;
for (ll i = 1; i <= n - 1; ++i) {
ll x, y;
cin >> x >> y;
g[x].push_back(y);
g[y].push_back(x);
}
add(rt, 1);
dfs(rt, -1);
ll num = ((n * (n - 1) % mod * qpow(2, mod - 2) % mod - cntRev - cntNum) % mod + mod) % mod;
ll ans = f[rt] * (cntRev + num * qpow(2, mod - 2) % mod) % mod;
cout << ans << endl;
}