5339. 【NOIP2017提高A组模拟8.25】玫瑰花精

Description
5339. 【NOIP2017提高A组模拟8.25】玫瑰花精_第1张图片

Input
5339. 【NOIP2017提高A组模拟8.25】玫瑰花精_第2张图片

output
这里写图片描述

Sample Input

7 11
1 15
1 123123
1 3
1 5
2 123123
2 15
1 21
2 3
1 6
1 7
1 8

Sample Output

1
7
4
2
7
4
1
3

做法:可以考虑线段树。首先我们对区间[1..n]建立一棵线段树。对于每一个节点,
维护 4 个值。分别是 l,r,mid,p。l 表示在当前结点线段树所在区间最左边的花精
所在的位置,r 表示最右边的花精所在的位置。mid 表示在这个小区间[l,r]中的
两只花精之间的最长距离除以 2 后的值。p 表示取 mid 值时所在的紧邻的两只
花精的中间位置,也就是在[l,r]中的答案值。
对于 1 询问:访问线段树的第一个节点,我们比较 l-1,n-r,mid 的值哪
个更大,就选哪个,它们的答案依次是 1,n,p。假设我们求得的位置是 fairy[x]。
然后访问[fairy[x],fairy[x]]所在的线段树的叶子节点,初始化它的值,然后回溯,
进行合并。对于 tr[x].l 与 tr[x].r 可以通过两个儿子的 l,r 信息得出。对于 tr[x].mid
值,首先在左右儿子的 mid 值中去一个最大的值。其次考虑一种情况,就是夹在
两个线段之间的距离,可以通过(tr[x+x+1].l-tr[x+x].r) / 2 的值得出在于 mid
进行比较,然后 p 就随着 mid 的值的更新而更新。
对于 2 询问:访问询问花精所在的位置,直接将它的叶子节点
[fairy[x],fairy[x]]删除,然后回溯时,再做一次合并操作。
细节蛮多的。。。

代码如下:

#include 
#include 
#include 
#include 
#define N 1000007
using namespace std;
struct tree
{
    int l, r, mid, p;
}f[N];
int n, m, a[N];

int read()
{
    int s = 0;
    char ch = getchar();
    while (ch < '0' || ch > '9')    ch = getchar();
    while (ch >= '0' && ch <= '9')  s = s * 10 + ch - '0', ch = getchar();
    return s;
}

void update(int x)
{
    if (f[x << 1].l > 0)    f[x].l = f[x << 1].l;
    else f[x].l = f[x << 1 | 1].l;
    if (f[x << 1 | 1].r > 0)    f[x].r = f[x << 1 | 1].r;
    else f[x].r = f[x << 1].r;
    f[x].mid = f[x << 1].mid;
    f[x].p = f[x << 1].p;
    if (f[x << 1].r > 0 && f[x << 1 | 1].l > 0)
    {
        int cmp = (f[x << 1 | 1].l - f[x << 1].r) / 2;
        if (cmp > f[x].mid)
        {
            f[x].mid = cmp;
            f[x].p = (f[x << 1].r + f[x << 1 | 1].l) / 2;
        }
        if (f[x << 1 | 1].mid > f[x].mid)
        {
            f[x].mid = f[x << 1 | 1].mid;
            f[x].p = f[x << 1 | 1].p;
        }
    }
}

void change(int p, int l, int r, int x, int judge)
{
    if (l == r)
    {
        if (judge == 2)
        {
            f[p].l = 0;
            f[p].r = 0;
            f[p].p = 0;
            f[p].mid = 0;
        }
        else
        {
            f[p].l = l;
            f[p].r = r;
            f[p].p = 0;
            f[p].mid = 0;
        }
        return;
    }
    int mid = (l + r) / 2;
    if (x <= mid)   change(p << 1, l, mid, x, judge);
    else change(p << 1 | 1, mid + 1, r, x, judge);
    update(p);
}

int main()
{
    n = read(), m = read();
    int x, y;
    while (m--)
    {
        y = read(), x = read();
        if (y == 1)
        {
            if (f[1].l == 0)    a[x] = 1;
            else
            {
                int cmp = -2000000;
                if (f[1].l - 1 > cmp)
                {
                    cmp = f[1].l - 1;
                    a[x] = 1;
                }
                if (f[1].mid > cmp)
                {
                    cmp = f[1].mid;
                    a[x] = f[1].p;
                }
                if (n - f[1].r > cmp)
                {
                    cmp = n - f[1].r;
                    a[x] = n;
                }
            }
            printf("%d\n", a[x]);
            change(1, 1, n, a[x], 1);
        }
        else change(1, 1, n, a[x], 2);
    }
}

你可能感兴趣的:(线段树)