HDU 4605 (主席樹)
阿新 • • 發佈:2019-02-14
題意:有一棵樹二叉,每個節點有一個數字。每次詢問一個節點和一個數字,問這個數字經過這個節點的概率。一個數字從根開始往下走,如果走過的節點數字和他相同,就停在這裡;如果節點數字比他大,向左向右的概率都是1/2;否則向左的概率是1/8,向右的概率是7/8。
對於每個詢問,需要統計他到根節點路徑之間的資訊。所以從根開始開主席數,線段數記錄走向左兒子的某個數字的個數和走向右兒子的某個數字的個數。這樣對於每一個詢問,找到a,b,c,d四個值,分別代表向左走的比詢問大的數,向右走的比詢問大的數,向左走的比詢問小的數,向右走的比詢問大的數。無解當且僅當詢問到根路徑有等於詢問的數;否則把這四個數整理一下就是答案了。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
#define N 100005
#define maxn 200005
#define maxm maxn*60
struct node {
int l, r;
int lnum, rnum;
}tree[maxm];
int tot, T[N];
int n, m, q;
int Left[N], Right[N], fa[N];
int qu[N][2];
vector <int> num;
int gg[maxn], cnt, w[N];
void lisanhua () {///離散化
sort (num.begin(), num.end ());
int sz = num.size ();
cnt = 0;
for (int i = 0; i < sz; i++) {
if (!i || num[i] != num[i-1]) {
gg[++cnt] = num[i];
}
}
for (int i = 1; i <= n; i++) {
w[i] = lower_bound (gg+1, gg+1+cnt, w[i])-gg;
}
for (int i = 1; i <= q; i++) {
qu[i][1] = lower_bound (gg+1, gg+1+cnt, qu[i][1])-gg;
}
}
int build_tree (int l, int r) {
int root = tot++;
tree[root].lnum = tree[root].rnum = 0;
if (l == r) return root;
int mid = (l+r)>>1;
tree[root].l = build_tree (l, mid);
tree[root].r = build_tree (mid+1, r);
return root;
}
int update (int root, int pos, int val, int from) {
int new_root = tot++, tmp = new_root;
int l = 1, r = cnt;
tree[new_root].lnum = tree[root].lnum;
tree[new_root].rnum = tree[root].rnum;
if (from == 0) tree[new_root].lnum += val;
else tree[new_root].rnum += val;
while (l < r) {
int mid = (l+r)>>1;
if (mid >= pos) {
tree[new_root].r = tree[root].r;
tree[new_root].l = tot++;
root = tree[root].l;
new_root = tree[new_root].l;
r = mid;
}
else {
tree[new_root].l = tree[root].l;
tree[new_root].r = tot++;
root = tree[root].r;
new_root = tree[new_root].r;
l = mid+1;
}
tree[new_root].lnum = tree[root].lnum;
tree[new_root].rnum = tree[root].rnum;
if (from == 0) {
tree[new_root].lnum += val;
}
else tree[new_root].rnum += val;
}
return tmp;
}
int d[N];
struct Q {
int u, from;
};
void bfs (int s) {
d[s] = 0;
T[s] = T[n+1];
queue <Q> q; while (!q.empty ()) q.pop (); q.push ((Q){s, 0});
while (!q.empty ()) {
Q tmp = q.front (); q.pop (); int u = tmp.u; int from = tmp.from;
if (fa[u] != -1) T[u] = update (T[fa[u]], w[fa[u]], 1, from);
if (Left[u] != -1) {
d[Left[u]] = d[u]+1;
q.push ((Q){Left[u], 0});
}
if (Right[u] != -1) {
d[Right[u]] = d[u]+1;
q.push ((Q){Right[u], 1});
}
}
}
int query_more (int root, int num, int from) {
int ans = 0;
int l = 1, r = cnt;
while (r >= l) {
if (l == r) {
if (l > num) {
if (from == 0) ans += tree[root].lnum;
else ans += tree[root].rnum;
}
break;
}
int mid = (l+r)>>1;
if (mid <= num) {
root = tree[root].r;
l = mid+1;
}
else {
if (from == 0) ans += tree[tree[root].r].lnum;
else ans += tree[tree[root].r].rnum;
root = tree[root].l;
r = mid;
}
}
return ans;
}
int query_less (int root, int num, int from) {
int ans = 0;
int l = 1, r = cnt, mid = (l+r)>>1;
while (r >= l) {
if (l == r) {
if (l < num) {
if (from == 0) ans += tree[root].lnum;
else ans += tree[root].rnum;
}
break;
}
int mid = (l+r)>>1;
if (mid >= num) {
root = tree[root].l;
r = mid;
}
else {
if (from == 0) ans += tree[tree[root].l].lnum;
else ans += tree[tree[root].l].rnum;
root = tree[root].r;
l = mid+1;
}
}
return ans;
}
void solve () {
tot = 0;
T[n+1] = build_tree (1, cnt);
int root;
for (int i = 1; i <= n; i++) if (fa[i] == -1) {
root = i;
break;
}
bfs (root);
for (int i = 1; i <= q; i++) { //cout << i << endl;
int u = qu[i][0], num = qu[i][1], father = (u == root ? n+1 : fa[u]);
int aa, bb, cc, dd;
aa = query_more (T[u], num, 0), bb = query_more (T[u], num, 1);
cc = query_less (T[u], num, 0), dd = query_less (T[u], num, 1);
int equ = d[u]-aa-bb-cc-dd;//和這個數字相等的
if (equ) {
printf ("0\n");
continue;
}
printf ("%d %d\n", dd, aa+bb+3*(cc+dd));
}
}
int main () {
//freopen ("more.in", "r", stdin);
int t;
scanf ("%d", &t);
while (t--) {
scanf ("%d", &n);
num.clear ();
for (int i = 1; i <= n; i++) {
scanf ("%d", &w[i]);
num.push_back (w[i]);
Left[i] = Right[i] = fa[i] = -1;
}
scanf ("%d", &m);
for (int i = 0; i < m; i++) {
int u, a, b; scanf ("%d%d%d", &u, &a, &b);
Left[u] = a, Right[u] = b;
fa[a] = u, fa[b] = u;
}
scanf ("%d", &q);
for (int i = 1; i <= q; i++) {
scanf ("%d%d", &qu[i][0], &qu[i][1]);
num.push_back (qu[i][1]);
}
lisanhua ();
solve ();
}
return 0;
}