codeforce 1326 E. Bombs(思维 + 线段树)

codeforce 1326 E. Bombs(思维 + 线段树)_第1张图片


答案具有单调性, a n s i − 1 ≥ a n s i ans_{i - 1} \geq ans_{i} ansi1ansi,考虑枚举 x x x,判断 a n s i < x ans_i < x ansi<x 是否成立。

a n s i < x ans_i < x ansi<x 成立,则所有 ≥ x \geq x x 的值都要被炸掉,把这些值拿出来按下标排序,最左边的数右边要有至少 n − x + 1 n - x + 1 nx+1 个炸弹,最右边的数至少要有 1 1 1 个炸弹,第 t t t 个数的右边至少要有 n − x + 1 − t + 1 n - x + 1 -t + 1 nx+1t+1 个炸弹。

对于每个 i i i,从大到小枚举 x x x,若 ≥ x \geq x x 都能被炸弹炸掉,则 a n s i < x ans_i < x ansi<x。对于所有 ≥ x \geq x x 的值,维护每个数字需要的炸弹数量,即炸弹需求量,在 q [ i ] q[i] q[i] 放一个炸弹,则 [ 1 , q [ i ] ] [1,q[i]] [1,q[i]] 的数值对炸弹的需求量减一,枚举 x − 1 x - 1 x1,将 x − 1 x - 1 x1 插入序列,则 [ 1 , p o s [ x − 1 ] ] [1,pos[x - 1]] [1,pos[x1]] 的炸弹需求量加一,只要当前这个序列任意一个炸弹需求量大于0,则表明答案 a n s i > x ans_i > x ansi>x,这个可以用线段树维护区间最值。

由于 a n s i ans_i ansi 具有单调性,因此 x x x 只需要枚举一遍,复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)


代码:

#include
using namespace std;
const int maxn = 3e5 + 10;
int n,p[maxn],q[maxn],ans[maxn],pos[maxn];
struct seg_tree {
	int val[maxn << 2],add[maxn << 2];
	#define lson rt << 1,l,mid
	#define rson rt << 1 | 1,mid + 1,r
	void build(int rt,int l,int r) {
		add[rt] = val[rt] = 0;
		if (l == r) return ;
		int mid = l + r >> 1;
		build(lson); build(rson);
	}
	void pushdown(int rt) {
		if (!add[rt]) return ;
		val[rt << 1] += add[rt];
		add[rt << 1] += add[rt];
		val[rt << 1 | 1] += add[rt];
		add[rt << 1 | 1] += add[rt];
		add[rt] = 0;
	}
	void update(int L,int R,int v,int rt,int l,int r) {
		if (L <= l && r <= R) {
			val[rt] += v;
			add[rt] += v;
			return ;
		}
		pushdown(rt);
		int mid = l + r >> 1;
		if (L <= mid) update(L,R,v,lson);
		if (mid + 1 <= R) update(L,R,v,rson);
		val[rt] = max(val[rt << 1],val[rt << 1 | 1]);
	}
}tree;
int main() {
	scanf("%d",&n);
	for (int i = 1; i <= n; i++) {
		scanf("%d",&p[i]);
		pos[p[i]] = i;
	}
	for (int i = 1; i <= n; i++)
		scanf("%d",&q[i]);	
	tree.build(1,1,n);
	int cur = n;
	tree.update(1,pos[cur],1,1,1,n);
	for (int i = 1; i <= n; i++) {
		ans[i] = cur;
		tree.update(1,q[i],-1,1,1,n);
		while (cur > 1 && tree.val[1] <= 0) {
			cur--;
			tree.update(1,pos[cur],1,1,1,n);
		}
	}
	for (int i = 1; i <= n; i++)
		printf("%d ",ans[i]);
	return 0;
}

你可能感兴趣的:(codeforce 1326 E. Bombs(思维 + 线段树))