二维线段树之降维打击

COCI 2017/2018 ROUND#1
Deda

Little Marica is making up a nonsensical unusual fairy tale and is telling to her grandfather who keeps interrupting her and asking her stupid intriguing questions.

In Marica’s fairy tale, N children, denoted with numbers from 1 to N by their age (from the youngest denoted with 1, to the oldest denoted with N ), embarked on a train ride. The train leaves from the station 0 and stops in order at stations 1, 2, 3 … to infinity.

Each of the following Marica’s statements is of the form: “At stop X , child A got out” , where the order of these statements is completely arbitrary. In other words, it does not depend on the station order. Her grandfather sometimes asks a question of the form: “Based on the statements so far, of the children denoted with a number greater than or equal to B , who is the youngest child that rode for Y or less stops?” If at the moment the grandfather asks the question it hasn’t been said so far that a child is getting off the train, we assume that the child is riding for an infinite amount of stops.

Marica must give a correct answer to each of her grandfather’s questions, otherwise the grandfather will get mad and go to sleep. The answer must be correct in the moment when the grandfather asks the question, while it can change later given Marica’s new statements, but that doesn’t matter. Write a program that tracks Marica’s statements and answers her grandfather’s questions.

INPUT

The first line of input contains the positive integers N and Q (2 ≤ N , Q ≤ 200 000), the
number of children and the number of statements. Each of the following Q lines describes:
● either Marica’s statement of the form “M” X A , where “M” denotes Marica, and X and
A are positive integers (1 ≤ X ≤ 1 000 000 000, 1 ≤ A ≤ N ) from the task,
● or her grandfather’s question of the form “D” Y B , where “D” denotes the grandfather,
and Y and B are positive integers (1 ≤ Y ≤ 1 000 000 000, 1 ≤ B ≤ N ) from the task.
All of Marica’s statements correspond to different children and at least one line in the input is
her grandfather’s question.

OUTPUT

For each grandfather’s question, output the number of the required child in its own line. If no
such child exists, output -1.

input input

3 4
M 10 3
M 5 1
D 20 2
D 5 1
10 10
M 20 10
D 1 9
M 2 3
D 17 10
M 20 2
D 8 2
M 40 1
D 25 2
M 33 9
D 37 9

output output

3
1
-1
-1
3
2
9


题意

一共n个人
两种操作
M X A表示 A走了X站
D Y B表示询问满足条件

{idBstopsY { i d ≥ B s t o p s ≤ Y

的人中id最小的是谁,不存在则-1


解法

如果用上一篇的二维线段树,在二维平面中以 id i d 为横轴, stop s t o p 为纵轴,每次M都新加一个值为stop的点 P(id,stop)=stop P ( i d , s t o p ) = s t o p ,然后询问的则是一个矩形内所有点的最小值,用二维线段树维护矩形内最小值即可,但是二维线段树空间时间都会比一维的大,上一篇的题目时间限制为3s ,这一题为1s,所以不能用二维线段树。

这一题问的是最小值,我们知道在线段树上,左边的点坐标就是小的,点的值也可以维护最小值。

所以这一题以id为轴建立线段树,以stop为点的值,维护stop的区间最小值。 对于每次询问 D Y B D   Y   B ,则先取 [B,+] [ B , + ∞ ] 上的最小值,
每次递归时检查区间的最小值是否小于等于Y,若不是,那么区间内不存在合适的点。若是,则判断当前区间是否包含于 [B,+] [ B , + ∞ ]
若是则找到id最小的(即最左边的)点来更新答案,且当左边有答案时不再向右走以减少浪费时间。

#include<iostream>
#include<stdio.h>
#include<string>
#include<string.h>
#include<algorithm>
#include<vector>
#include<set>
#include<math.h>
#include<map>
#include<stack>
using namespace std;
typedef long long LL;
const int MAX = 2e9;
int tree[2000000];
int answer;
void build(int t, int l, int r)
{
    tree[t] = MAX;
    if (l == r)
    {
        return;
    }
    int mid = l + r >> 1;
    build(t << 1, l, mid);
    build(t << 1 | 1, mid + 1, r);
}
void update(int temp, int left, int right, int B, int Y)
{
    if (left == right)
    {
        tree[temp] = Y;
        return;
    }
    int mid = left + right >> 1;
    if (B <= mid)
        update(temp << 1, left, mid, B, Y);
    else
        update(temp << 1 | 1, mid + 1, right, B, Y);
    tree[temp] = min(tree[temp << 1], tree[temp << 1 | 1]);
}
void query(int temp, int left, int right, int Y, int B)
{
    if (left == right)
    {
        answer = min(answer, left);
        return;
    }
    int mid = left + right >> 1;
    if (B < left)
    {
        if (tree[temp << 1] <= Y)
            query(temp << 1, left, mid, Y, B);
        else
            query(temp << 1 | 1, mid + 1, right, Y, B);
    }
    else
    {
        if (B <= mid && tree[temp << 1] <= Y)
            query(temp << 1, left, mid, Y, B);
        if (tree[temp << 1 | 1] <= Y)
            query(temp << 1 | 1, mid + 1, right, Y, B);
    }
}
int main()
{
    int N, Q;
    scanf("%d%d", &N, &Q);
    build(1, 1, N);
    while (Q--)
    {
        char s[5];
        int Y, B;
        scanf("%s%d%d", s, &Y, &B);
        if (s[0] == 'M')
            update(1, 1, N, B, Y);
        else
        {
            answer = MAX;
            query(1, 1, N, Y, B);
            if (answer > N)
                printf("-1\n");
            else
                printf("%d\n", answer);
        }
    }
    return 0;
}

总结

这一题要维护两个最值,要知道一维线段树中左边的点比右边的坐标值小,再在每个点上维护一个最小值即可

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值