codeforce 1326 E. Bombs(思維 + 線段樹)

在這裏插入圖片描述


答案具有單調性,ansi1ansians_{i - 1} \geq ans_{i},考慮枚舉 xx,判斷 ansi<xans_i < x 是否成立。

ansi<xans_i < x 成立,則所有 x\geq x 的值都要被炸掉,把這些值拿出來按下標排序,最左邊的數右邊要有至少 nx+1n - x + 1 個炸彈,最右邊的數至少要有 11 個炸彈,第 tt 個數的右邊至少要有 nx+1t+1n - x + 1 -t + 1 個炸彈。

對於每個 ii,從大到小枚舉 xx,若 x\geq x 都能被炸彈炸掉,則 ansi<xans_i < x。對於所有 x\geq x 的值,維護每個數字需要的炸彈數量,即炸彈需求量,在 q[i]q[i] 放一個炸彈,則 [1,q[i]][1,q[i]] 的數值對炸彈的需求量減一,枚舉 x1x - 1,將 x1x - 1 插入序列,則 [1,pos[x1]][1,pos[x - 1]] 的炸彈需求量加一,只要當前這個序列任意一個炸彈需求量大於0,則表明答案 ansi>xans_i > x,這個可以用線段樹維護區間最值。

由於 ansians_i 具有單調性,因此 xx 只需要枚舉一遍,複雜度 O(nlogn)O(n\log n)


代碼:

#include<bits/stdc++.h>
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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章