HDU-4605 Magic Ball Game(樹狀數組+離線操作)

題目鏈接: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。

7^{x}/2^{y}的形式輸出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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章