題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=4605
題目大意:有一棵n個節點的有根樹。每個節點都有一個權值w,同時樹中的節點,要麼沒有兒子節點,要麼就剛好有兩個兒子節點。現在要在根節點放一個權值爲X的球。當球落到節點 i 的時候,球都會有如下三種情況:
1、如果X=w[i]或者 i 沒有兒子節點的話,球就會停在這個節點,不繼續往下落;
2、如果X < w[i] 的話,球有1/2的概率落到左兒子,有1/2的概率落到右兒子;
3、如果X > w[i] 的話,球有1/8的概率落到左兒子,有7/8的概率落到右兒子。
現在有q次詢問,每次給出一個v和X,表示詢問在根節點放置一個權值爲X的球的話,有多大的概率落到節點v。
以的形式輸出x和y,如果無法到達就直接輸出0。
題目思路:對於每次查詢,我們可以知道,只與根節點到節點v這條路徑上的信息有關。
如果在這條路徑上有一個非 v 的節點的權值等於X的話,那麼就無法到達節點v了。
現在我們假設在這條路徑上,比X大同時是走左兒子的節點個數爲MAX_L,比X大同時是走右兒子的節點個數爲MAX_R,比X小同時是走左兒子的節點個數爲MIN_L,比X小同時是走右兒子的節點個數爲MIN_R。
那麼最終的答案x = MAX_R,y = MIN_L + MIN_R + MAX_L * 3 + MAX_R * 3。
現在我們來考慮要如何維護這些信息。由於每次的查詢只和一條鏈上的信息有關,所以我們可以考慮將所有的查詢都離線下來。只做一遍dfs來維護這些信息,因爲在從根節點開始的dfs的過程中,遍歷到節點u的話,正好是維護了從根節點到節點u的所有信息。
而我們正好可以用兩個樹狀數組來維護這些信息,一棵維護走左兒子的節點信息,一棵維護走右兒子的節點信息。樹狀數組中維護的是權值爲 i 的節點的個數,那麼就可以通過區間查詢知道,權值大於 X 的節點有多少個了。(由於權值最大有1e9,所以還得離散化一下)。
這樣就可以通過離線操作求出最終的結果了。
具體實現看代碼:
#include <bits/stdc++.h>
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pb push_back
#define MP make_pair
#define all(v) v.begin(),v.end()
#define IOS ios::sync_with_stdio(false)
#define FIN freopen("in.txt","r",stdin)
#define fuck(x) cout<<"["<<#x<<" "<<x<<"]\n"
using namespace std;
typedef long long ll;
typedef pair<int, int>pii;
typedef pair<ll, ll>pll;
const int MX = 1e5 + 7;
const int mod = 998244353;
int n, m, q, N, _;
int val[MX];
int ls[MX], rs[MX];
vector<int> has;
vector<pii>que[MX];
pii ans[MX];
int fa[MX], root;
int get_id(int x) {
return lower_bound(all(has), x) - has.begin() + 1;
}
struct BIT {
int n;
int a[MX * 2];
int lowbit(int x) {return x & -x;}
void init(int _n) {
n = _n;
for (int i = 0; i <= n; i++) a[i] = 0;
}
void add(int x, int d) {
for (; x <= n; x += lowbit(x))
a[x] += d;
}
int sum(int x) {
int res = 0;
for (; x; x -= lowbit(x))
res += a[x];
return res;
}
} TL, TR;
void dfs(int u) {
for (auto now : que[u]) {
if (u == root) {
ans[now.se] = MP(0, 0);
continue;
}
int w = get_id(now.fi);
int a = TL.sum(N), b = TL.sum(w), c = TL.sum(w - 1);
a -= b; b -= c;
int a2 = TR.sum(N), b2 = TR.sum(w), c2 = TR.sum(w - 1);
a2 -= b2; b2 -= c2;
if (b || b2) ans[now.se] = MP(-1, -1);
else ans[now.se] = MP(c2, a + c * 3 + a2 + c2 * 3);
}
if (ls[u]) {
int w = get_id(val[u]);
TL.add(w, 1);
dfs(ls[u]);
TL.add(w, -1);
TR.add(w, 1);
dfs(rs[u]);
TR.add(w, -1);
}
}
int main() {
// FIN;
for (scanf("%d", &_); _; _--) {
scanf("%d", &n);
has.clear();
for (int i = 1; i <= n; i++) {
scanf("%d", &val[i]);
que[i].clear();
fa[i] = ls[i] = rs[i] = 0;
has.pb(val[i]);
}
scanf("%d", &m);
for (int i = 1; i <= m; i++) {
int u, a, b;
scanf("%d%d%d", &u, &a, &b);
fa[a] = fa[b] = u;
ls[u] = a; rs[u] = b;
}
scanf("%d", &q);
for (int i = 1; i <= q; i++) {
int v, X;
scanf("%d%d", &v, &X);
que[v].pb(MP(X, i));
has.pb(X);
}
sort(all(has));
has.erase(unique(all(has)), has.end());
N = has.size();
TL.init(N); TR.init(N);
for (int i = 1; i <= n; i++) {
if (fa[i] == 0) {
root = i;
dfs(i);
break;
}
}
for (int i = 1; i <= q; i++) {
if (ans[i].fi == -1) printf("0\n");
else
printf("%d %d\n", ans[i].fi, ans[i].se);
}
}
return 0;
}