2019CCPC网络赛 - B. array

题意:

给定一个长为 n 的排列,然后给出 m 个操作,① (1, pos),表示 a[pos] 加上 1000w;② (2, r, k),询问大于等于 k 的最小的不在 a[1] … a[r] 中出现的数,强制在线。(n, m <= 1e5)

链接:

https://cn.vjudge.net/problem/HDU-6703

题解:

注意到进行过修改操作后的数不可能成为询问的答案,答案最大为 n + 1,则修改操作对应为删除操作。考虑建立权值线段树,每个结点存放对应下标,则询问转化为在区间 [k, n + 1] 中找到第一个下标大于 r 的值。线段树维护区间最值,删除操作对应把下标赋0,查询时候定位到相应区间后,再判断是否继续进行单点查询,详见代码。

参考代码:
#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define pb push_back
#define sz(a) ((int)a.size())
#define mem(a, b) memset(a, b, sizeof a)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
#define lnum (mid - l + 1)
#define rnum (r - mid)
const int maxn = 1e5 + 5;
const int maxm = 2e5 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;

int a[maxn], mx[maxn << 2];
int n, m;

void build(int l, int r, int rt){

	if(l == r) { mx[rt] = a[l]; return; }
	int mid = gmid;
	build(l, mid, lson);
	build(mid + 1, r, rson);
	mx[rt] = max(mx[lson], mx[rson]);
}

void update(int l, int r, int rt, int pos, int val){

	if(l == r) { mx[rt] = val; return; }
	int mid = gmid;
	if(pos <= mid) update(l, mid, lson, pos, val);
	else update(mid + 1, r, rson, pos, val);
	mx[rt] = max(mx[lson], mx[rson]);
}

int dfs(int l, int r, int rt, int val){

	if(l == r) return l;
	int mid = gmid;
	if(mx[lson] > val) return dfs(l, mid, lson, val);
	else return dfs(mid + 1, r, rson, val);
}

int query(int l, int r, int rt, int L, int R, int val){

	if(l >= L && r <= R){

		if(mx[rt] <= val) return 0;
		return dfs(l, r, rt, val);
	}
	int mid = gmid;
	if(L <= mid) if(int ret = query(l, mid, lson, L, R, val)) return ret;
	if(R > mid) if(int ret = query(mid + 1, r, rson, L, R, val)) return ret;
	return 0;
}

int main() {

//    ios::sync_with_stdio(0); cin.tie(0);
	int t; scanf("%d", &t);
	while(t--){

		scanf("%d%d", &n, &m);
		for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
		++n; a[n] = n; build(1, n, 1);
		for(int i = 1; i <= n; ++i) update(1, n, 1, a[i], i);
		int ret = 0;
		while(m--){

			int opt, x, y; scanf("%d%d", &opt, &x);
			if(opt == 1){

				x ^= ret;
				if(!a[x]) continue;
				update(1, n, 1, a[x], n);
				a[x] = 0;
			}
			else{

				scanf("%d", &y);
				x ^= ret, y ^= ret;
				ret = query(1, n, 1, y, n, x);
				printf("%d\n", ret);
			}
		}
	}
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值