hihoCoder 1169 猜数字 (线段树,离线处理)

题意:

每次询问求出区间最接近k的数对应的差。

题解:

离线操作,两次排序,计算两次,第一次将询问和数字根据k从小到大排序,碰到询问只要查询区间的最大值跟定是最靠近k的,相反第二次是从大到小排序,求最小值是最靠近k的,两次计算的值取最小值即可。

#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<string>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<stack>
#define B(x) (1<<(x))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int oo = 0x3f3f3f3f;
const ll OO = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-9;
#define lson rt<<1
#define rson rt<<1|1
void cmax(int& a, int b){ if (b > a)a = b; }
void cmin(int& a, int b){ if (b < a)a = b; }
void cmax(ll& a, ll b){ if (b > a)a = b; }
void cmin(ll& a, ll b){ if (b < a)a = b; }
void cmax(double& a, double b){ if (a - b < eps) a = b; }
void cmin(double& a, double b){ if (b - a < eps) a = b; }
void add(int& a, int b, int mod){ a = (a + b) % mod; }
void add(ll& a, ll b, ll mod){ a = (a + b) % mod; }
const ll MOD = 1000000007;
const int maxn = 210000;
struct SegTree{
	int l, r, max, min;
	int mid(){ return (l + r) >> 1; }
}tree[maxn << 2];

struct Query{
	int l, r, k, id, f;
}q[maxn << 1];
int ans[maxn];

void push_up(int rt){
	tree[rt].max = max(tree[lson].max, tree[rson].max);
	tree[rt].min = min(tree[lson].min, tree[rson].min);
}

void build(int l, int r, int rt){
	tree[rt].l = l;
	tree[rt].r = r;
	tree[rt].max = -oo;
	tree[rt].min = oo;
	if (l == r) return;
	int mid = (l + r) >> 1;
	build(l, mid, lson);
	build(mid + 1, r, rson);
	push_up(rt);
}

void update(int p, int v, int rt){
	if (tree[rt].l == tree[rt].r&&tree[rt].r == p){
		tree[rt].max = tree[rt].min = v;
		return;
	}
	int mid = tree[rt].mid();
	if (p <= mid) update(p, v, lson);
	else if (p >= mid + 1) update(p, v, rson);
	push_up(rt);
}

int get_max(int l, int r, int rt){
	if (l <= tree[rt].l && tree[rt].r <= r){
		return tree[rt].max;
	}
	int mid = tree[rt].mid();
	int res = -oo;
	if (l <= mid) cmax(res, get_max(l, r, lson));
	if (mid + 1 <= r) cmax(res, get_max(l, r, rson));
	return res;
}

int get_min(int l, int r, int rt){
	if (l <= tree[rt].l && tree[rt].r <= r){
		return tree[rt].min;
	}
	int mid = tree[rt].mid();
	int res = oo;
	if (l <= mid) cmin(res, get_min(l, r, lson));
	if (mid + 1 <= r) cmin(res, get_min(l, r, rson));
	return res;
}

bool cmp1(Query q1, Query q2){
	if (q1.k == q2.k)
		return q1.f < q2.f;
	return q1.k < q2.k;
}

bool cmp2(Query q1, Query q2){
	if (q1.k == q2.k)
		return q1.f < q2.f;
	return q1.k > q2.k;
}

int main(){
	//freopen("E:\\read.txt", "r", stdin);
	int T, n, Q, nn, cas = 1;
	scanf("%d", &T);
	while (T--){
		scanf("%d %d", &n, &Q);
		for (int i = 1; i <= n; i++){
			scanf("%d", &q[i].k);
			q[i].l = i;
			q[i].f = 0;
		}
		nn = n;
		for (int i = 1; i <= Q; i++){
			++nn;
			scanf("%d %d %d", &q[nn].l, &q[nn].r, &q[nn].k);
			q[nn].f = 1;
			q[nn].id = i;
		}
		build(1, n, 1);
		sort(q + 1, q + 1 + nn, cmp1);
		for (int i = 1; i <= nn; i++){
			if (q[i].f == 0) update(q[i].l, q[i].k, 1);
			else ans[q[i].id] = q[i].k - get_max(q[i].l, q[i].r, 1);
		}
		build(1, n, 1);
		sort(q + 1, q + 1 + nn, cmp2);
		for (int i = 1; i <= nn; i++){
			if (q[i].f == 0) update(q[i].l, q[i].k, 1);
			else{
				int tmp = get_min(q[i].l, q[i].r, 1);
				if (tmp == oo) continue;
				cmin(ans[q[i].id], tmp - q[i].k);
			}
		}
		printf("Case #%d:\n", cas++);
		for (int i = 1; i <= Q; i++)
			printf("%d\n", ans[i]);
	}
	return 0;
}



你可能感兴趣的:(hihoCoder 1169 猜数字 (线段树,离线处理))