hdu4605
hdu4605
题意
给出一棵带权值的树,多个查询 \(v, X\),某个重量为 \(X\) 的小球从根结点出发,根据 \(X\) 与当前结点权值的大小关系决定走左右子结点的概率,问到达 \(v\) 结点的概率。
分析
先离散化,再树状数组维护路径上结点的值,查询离线处理。
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 5;
int l[MAXN], r[MAXN], c[MAXN];
vector<int> v1[MAXN], v2[MAXN];
int x[MAXN], y[MAXN], d[MAXN << 1];
int f[2][MAXN];
void update(int p, int k, int z) {
while(k < MAXN) {
f[p][k] += z;
k += k & -k;
}
}
int query(int p, int k) {
int a = 0;
while(k) {
a += f[p][k];
k -= k & -k;
}
return a;
}
void dfs(int u) {
for(int i = 0; i < v1[u].size(); i++) {
int a = v2[u][i], b = v1[u][i];
if((u != 1 && a == c[1]) || query(0, a) - query(0, a - 1) > 0 || query(1, a) - query(1, a - 1) > 0) x[b] = -1;
else {
int cnt01 = query(0, a - 1), cnt00 = query(0, MAXN - 1) - query(0, a);
int cnt11 = query(1, a - 1), cnt10 = query(1, MAXN - 1) - query(1, a);
y[b] = cnt00 + cnt10 + 3 * (cnt01 + cnt11);
x[b] = cnt11;
}
}
if(l[u]) {
update(0, c[u], 1);
dfs(l[u]);
update(0, c[u], -1);
update(1, c[u], 1);
dfs(r[u]);
update(1, c[u], -1);
}
}
int main() {
int T;
scanf("%d", &T);
while(T--) {
memset(l, 0, sizeof l);
memset(f, 0, sizeof f);
int n, m;
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
v1[i].clear();
v2[i].clear();
scanf("%d", &c[i]);
d[i] = c[i];
}
scanf("%d", &m);
while(m--) {
int u, a, b;
scanf("%d%d%d", &u, &a, &b);
l[u] = a;
r[u] = b;
}
int q;
scanf("%d", &q);
int cnt = n;
for(int i = 0; i < q; i++) {
int a, b;
scanf("%d%d", &a, &b);
v1[a].push_back(i);
v2[a].push_back(b);
d[++cnt] = b;
}
sort(d + 1, d + 1 + cnt);
int nn = unique(d + 1, d + 1 + cnt) - d - 1;
for(int i = 1; i <= n; i++) {
c[i] = lower_bound(d + 1, d + 1 + nn, c[i]) - d;
for(int j = 0; j < v2[i].size(); j++) v2[i][j] = lower_bound(d + 1, d + 1 + nn, v2[i][j]) - d;
}
dfs(1);
for(int i = 0; i < q; i++) {
if(x[i] == -1) printf("0\n");
else printf("%d %d\n", x[i], y[i]);
}
}
return 0;
}