E题,离线+树状数组

分析每一个位置i的数字Ai什么时候会被删掉,在遇见第一个i < j并且 a_i > a_j时就要删掉,也就是说在询问区间[L,R]中,如果i>=L并且这个i对应的那个j<=R就需要计算一次贡献,构建一个record数组record[i]代表位置i所对应那个j在哪里。显然这个record可以倒着扫一遍+树状数组解决。每找到一个j就可以在位置j加一次贡献,那么最后计算答案的时候就是计算[L,R]区间被加了多少次贡献。最后的一个问题就是询问[L,R]区间的贡献但是有可能[1,L-1]的数字所对应的j在区间[L,R]里面,就会算多贡献。我自己的处理手法就是离线之后排序,按照询问区间的左端点从小到大排序,然后询问的左端点就慢慢变大,没改变一次左端点就把当前左端点之前的每个位置的贡献减去,就可以保证不会有贡献被多余的计算。

int tree_Val[max_], limR,tree_Min[max_];
il int lowbit(int x) { return x & -x; }
void change(int x, int v,int *tree_) {
	while (x <= limR){
		tree_[x] += v;
		x += lowbit(x);
	}
}
int ask(int x, int* tree_) {
	int ans = 0;
	while (x > 0){
		ans += tree_[x];
		x -= lowbit(x);
	}
	return ans;
}
void change2(int x, int v, int* tree_) {
	while (x <= limR) {
		tree_[x] = min(tree_[x], v);
		x += lowbit(x);
	}
}
int ask2(int x, int* tree_) {
	int ans = inf;
	while (x > 0) {
		ans = min(ans, tree_[x]);
		x -= lowbit(x);
	}
	return ans;
}
int node[max_],vv[max_],vn,record[max_],ans[max_];
struct NN {
	int L, R, id;
} Que[max_];
bool cmp(NN& a, NN &b) {
	return a.L < b.L;
}
void solve() {
	int N = read(), Q = read();
	limR = N + 1;
	for (int i = 1; i <= N; i++)vv[i] = node[i] = read();
	sort(vv + 1, vv + 1 + N);
	vn = unique(vv + 1, vv + 1 + N) - vv - 1;
	for (int i = 1; i <= N; i++)node[i] = lower_bound(vv + 1, vv + 1 + vn, node[i]) - vv;
	memset(tree_Min, 127, sizeof(tree_Min));
	int ind;
	for (int i = N; i>= 1; i--) {
		ind = ask2(node[i] - 1, tree_Min);
		record[i] = ind;
		if (ind <= N)change(ind, 1, tree_Val);
		change2(node[i], i, tree_Min);
	}
	int L, R;
	for(int i = 1;i <= Q;i++){
		Que[i].L = read(), Que[i].R = read(); Que[i].id = i;
	}
	sort(Que + 1, Que + 1 + Q, cmp);
	int lasL = 0;
	for (int i = 1; i <= Q; i++) {
		for (int j = lasL + 1; j < Que[i].L; j++) {
			if (record[j] <= N)change(record[j], -1, tree_Val);
		}
		lasL = Que[i].L - 1;
		ans[Que[i].id] = ask(Que[i].R, tree_Val) - ask(Que[i].L - 1, tree_Val);
	}
	for (int i = 1; i <= Q; i++)	printf("%d\n", ans[i]);
}

全部评论

相关推荐

评论
3
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务