HDU6703.array(权值线段树)

题目描述:

给你一个Array{1,2...n}的数列,其中每个元素都是独立的,每个元素大小不大于1e5,长度也不大于1e5,现在有两种操作:

(1,pos):将pos位上的元素a[pos]变为a[pos]+1000000;

(2,r,k):询问当前数组中,不等于a[1],a[2]....a[r]且不小于k的元素的最小值。

思路:

因为元素数据范围不大,加上1000000就相当于删除,现在询问就变成了在[k,n+1]这个区间中寻找第一个下标大于r的,未被删除的元素。

所以可以建立权值线段树,并在权值线段树中维护下标的最大值,询问则转化为不小 于k的值里面,下标超过r的最小权值是多少。

这样,我们在查询过程中先走左子树(因为是权值线段树,左子树值更小),如果左子树中有下标大于r的就不必再走右子树了,否则一定在右子树中。这样询问就可以保证复杂度为O(nlogn)。

#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(int i=l;i<=r;++i)
#define per(i,r,l) for(int i=r;i>=l;--i)
#define pb push_back
#define mk make_pair
#define ll long long
const int inf = 1e9;
const int maxn = 1e5 + 10;
struct node {
	int l, r, pos;
}t[maxn << 2];
int a[maxn], b[maxn];
int lastans, n, m, t1, cmd;
void build(int u, int l, int r) {
	t[u].l = l, t[u].r = r;
	if (l == r) {
		t[u].pos = a[l];
		return;
	}
	int mid = (l + r) >> 1;
	build(u << 1, l, mid);
	build(u << 1 | 1, mid + 1, r);
	t[u].pos = max(t[u << 1].pos, t[u << 1 | 1].pos);
}
void update(int u, int pos) {
	int l = t[u].l, r = t[u].r;
	if (l == r) {
		t[u].pos = n + 1;
		return;
	}
	int mid = (l + r) >> 1;
	if (pos <= mid)update(u << 1, pos);
	else update(u << 1 | 1, pos);
	t[u].pos = max(t[u << 1].pos, t[u << 1 | 1].pos);
}
int solve(int u, int k) {
	int l = t[u].l, r = t[u].r;
	if (t[u].pos < k)return  inf;
	if (l == r) {
		return l;
	}
	if (t[u << 1].pos >= k)return solve(u << 1, k);
	else return solve(u << 1 | 1, k);
}
int GetAns(int u, int L, int R, int k) {
	int l = t[u].l, r = t[u].r;
	if (l == L && r == R) {
		return solve(u, k);
	}
	int mid = (l + r) >> 1;
	if (R <= mid)return GetAns(u << 1, L, R, k);
	else if (L > mid)return GetAns(u << 1 | 1, L, R, k);
	else return min(GetAns(u << 1, L, mid, k), GetAns(u << 1 | 1, mid + 1, R, k));
}
signed main() {
	ios::sync_with_stdio(NULL);
	cin.tie(0);
	int _;
	cin >> _;
	while (_--) {
		lastans = 0;
		cin >> n >> m;
		rep(i, 1, n + 1)a[i] = n + 1;
		rep(i, 1, n) {
			cin >> b[i];
			a[b[i]] = i;
		}
		build(1, 1, n + 1);
		rep(i, 1, m) {
			cin >> cmd;
			if (cmd == 1) {
				cin >> t1;
				t1 ^= lastans;
				update(1, b[t1]);
			}
			else {
				int k, r;
				cin >> r >> k;
				r ^= lastans, k ^= lastans;
				lastans = GetAns(1, k, n + 1, r + 1);
				cout << lastans << endl;
			}
		}
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值