ポータル
のアイデア:
「私は小さなカタツムリです」
namoからの参照は、リメイクを除いて、2人の教師と同じくらい強いことができ
ますか?親子関係を持つポイントペアが逆になっているかどうか、別のdfsシーケンスを検討してください。親子関係はありません。ポイントペアが逆になっているかどうかの確率は、それぞれ1 2 \ frac{1}{2}を占めています。21
dfsの序数を数え、サブツリーのdfsの序数を維持することを検討してください。現在のノードのdfsの序数は(∏ \ prod∏子ノードをルートとするサブツリーのdfs序数)×\ times×(子ノードの順列の数)
コード:
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;
}