【校内训练2019-03-17】胖

【思路要点】

  • 离线操作,我们需要求出各城市破产的时间来回答询问。
  • 考虑二分答案,我们需要能够回答形如 “ x x x 城市在 y y y 时刻遭受的损失” 的问题。
  • 对于一个修改,我们可以将其拆分为在 O ( L o g V ) O(LogV) O(LogV) 个节点处向下传导至多 O ( L o g V ) O(LogV) O(LogV) 层的损失,在询问时我们只需查询其至多 O ( L o g V ) O(LogV) O(LogV) 个祖先对对应深度造成的损失即可。
  • 修改的结果可以使用 v e c t o r vector vector 方便地可持久化,单次修改时间复杂度为 O ( L o g 2 V ) O(Log^2V) O(Log2V) ;询问单个节点对对应深度造成的损失需要在 v e c t o r vector vector 中二分,因此单次回答上文二分的询问,时间复杂度为 O ( L o g 2 V ) O(Log^2V) O(Log2V) ,得出一个城市破产的时间,时间复杂度为 O ( L o g Q L o g 2 V ) O(LogQLog^2V) O(LogQLog2V)
  • 考虑用整体二分代替二分,在 v e c t o r vector vector 中二分的步骤可改为单调地移动指针,可以省去瓶颈处在 v e c t o r vector vector 中二分的复杂度。
  • 修改时间复杂度 O ( Q L o g 2 V ) O(QLog^2V) O(QLog2V) v e c t o r vector vector 中元素总数 O ( Q L o g V ) O(QLogV) O(QLogV) ;整体二分的询问总数 O ( N L o g Q ) O(NLogQ) O(NLogQ) ,单次询问访问祖先数量 O ( L o g V ) O(LogV) O(LogV) ;指针移动总数 O ( Q L o g Q L o g V ) O(QLogQLogV) O(QLogQLogV)
  • 总时间复杂度 O ( N L o g 2 N ) O(NLog^2N) O(NLog2N)

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
const int MAXLOG = 15;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
struct BinaryIndexTree {
	int n, a[MAXN];
	void init(int x) {
		n = x;
		memset(a, 0, sizeof(a));
	}
	void modify(int x, int d) {
		for (int i = x; i <= n; i += i & -i)
			a[i] += d;
	}
	int query(int l, int r) {
		int ans = 0;
		for (int i = r; i >= 1; i -= i & -i)
			ans += a[i];
		for (int i = l - 1; i >= 1; i -= i & -i)
			ans -= a[i];
		return ans;
	}
} BIT;
vector <int> a[MAXN];
int n, s, m, q, val[MAXN];
pair <int, int> qry[MAXN];
int timer, dfn[MAXN], rit[MAXN], father[MAXN], depth[MAXN];
int death[MAXN], pointer[MAXN];
vector <pair <int, vector <int>>> b[MAXN];
vector <int> unit() {
	vector <int> ans (MAXLOG);
	for (int i = 0; i < MAXLOG; i++)
		ans[i] = 0;
	return ans;
}
vector <int> makev(int val) {
	vector <int> ans (MAXLOG);
	for (int i = 0; i < MAXLOG; i++, val >>= 1)
		ans[i] = val;
	return ans;
}
vector <int> recess(vector <int> ans) {
	for (int i = 0; i < MAXLOG - 1; i++)
		ans[i] = ans[i + 1];
	ans[MAXLOG - 1] = 0;
	return ans;
}
vector <int> operator + (vector <int> a, vector <int> b) {
	vector <int> ans (MAXLOG);
	for (int i = 0; i < MAXLOG; i++)
		ans[i] = a[i] + b[i];
	return ans;
}
vector <int> operator - (vector <int> a, vector <int> b) {
	vector <int> ans (MAXLOG);
	for (int i = 0; i < MAXLOG; i++)
		ans[i] = a[i] - b[i];
	return ans;
}
void modify(int x, int y) {
	static int pos[MAXLOG];
	static vector <int> goal[MAXLOG];
	int tot = 1; pos[0] = x, goal[0] = makev(y);
	while (tot < MAXLOG && pos[tot - 1] != 1) {
		pos[tot] = father[pos[tot - 1]];
		goal[tot] = recess(goal[tot - 1]);
		tot++;
	}
	vector <int> ex = unit();
	for (int i = tot - 1; i >= 0; i--) {
		vector <int> tmp = goal[i] - ex;
		b[pos[i]].emplace_back(m, b[pos[i]].back().second + tmp);
		ex = recess(ex + tmp);
	}
}
void dfs(int pos, int fa) {
	father[pos] = fa;
	depth[pos] = depth[fa] + 1;
	dfn[pos] = ++timer;
	for (auto x : a[pos])
		if (x != fa) dfs(x, pos);
	rit[pos] = timer;
}
void init() {
	read(n);
	for (int i = 1; i <= n; i++)
		read(val[i]);
	for (int i = 1; i <= n - 1; i++) {
		int x, y; read(x), read(y);
		a[x].push_back(y);
		a[y].push_back(x);
	}
	dfs(1, 0);
	for (int i = 1; i <= n; i++) {
		b[i].resize(1);
		b[i][0].first = 0;
		b[i][0].second = unit();
	}
	read(s);
	for (int i = 1; i <= s; i++) {
		int opt, x; read(opt), read(x);
		if (opt == 1) {
			int y; read(y); m++;
			modify(x, y);
		} else qry[++q] = make_pair(m, x);
	}
}
void debug() {
	for (int i = 1; i <= n; i++) {
		cerr << i << endl;
		for (auto x : b[i]) {
			cerr << x.first;
			for (auto y : x.second)
				cerr << ' ' << y;
			cerr << endl;
		}
		cerr << endl;
	}
}
int query(int pos, int timer) {
	int ans = 0;
	for (int i = 0; i < MAXLOG && pos != 0; i++, pos = father[pos]) {
		while (pointer[pos] < b[pos].size() - 1 && b[pos][pointer[pos] + 1].first <= timer) pointer[pos]++;
		ans += b[pos][pointer[pos]].second[i];
	}
	return ans;
}
bool cmp(pair <int, pair <int, int>> x, pair <int, pair <int, int>> y) {
	return x.second.first < y.second.first;
}
void gdeath() {
	static deque <pair <int, pair <int, int>>> deq;
	for (int i = 1; i <= n; i++)
		deq.emplace_back(i, make_pair(1, m + 1));
	int home = m + 1;
	while (!deq.empty()) {
		int pos = deq.front().first;
		pair <int, int> rng = deq.front().second;
		if (rng.first == rng.second) {
			death[pos] = rng.first;
			deq.pop_front();
			continue;
		}
		int mid = (rng.first + rng.second) / 2;
		if (mid < home) {
			home = 0;
			for (int i = 1; i <= n; i++)
				pointer[i] = 0;
			sort(deq.begin(), deq.end(), cmp);
			continue;
		}
		int tmp = query(pos, mid); home = mid;
		if (tmp >= val[pos]) deq.emplace_back(pos, make_pair(rng.first, mid));
		else deq.emplace_back(pos, make_pair(mid + 1, rng.second));
		deq.pop_front();
	}
}
void answer() {
	BIT.init(n);
	static vector <int> home[MAXN];
	for (int i = 1; i <= n; i++)
		home[death[i]].push_back(i);
	for (int i = 1, timer = 0; i <= q; i++) {
		while (timer < qry[i].first) {
			timer++;
			for (auto x : home[timer])
				BIT.modify(dfn[x], 1);
		}
		writeln(BIT.query(dfn[qry[i].second], rit[qry[i].second]));
	}
}
int main() {
	freopen("pang.in", "r", stdin);
	freopen("pang.out", "w", stdout);
	init();
	//debug();
	gdeath();
	answer();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值