noip模拟赛 无题

时间:2022-12-17 12:57:31

noip模拟赛 无题

分析:这道题和以前做过的模拟赛题很像:传送门.

      对于前30%的数据可以直接暴力求,k=1的数据利用线段树求区间最大值,没有修改操作可以用主席树.100%的数据主席树是肯定用不了的,观察到K非常小,可以用线段树来暴力维护.

      线段树记录每个区间内的第k小值(1≤k≤10),其它的操作没啥变化,就是pushup的时候要把两棵子树的信息给合并起来,用两个指针就好了.

      要维护的信息特别少,并且可以用线段树来维护的可以考虑用线段树来暴力维护.

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 100010;

struct node
{
    int minn[20];
}e[maxn << 2];

int n, m, tag[maxn << 2];

node hebing(node a, node b)
{
    int p1 = 1, p2 = 1;
    node temp;
    for (int i = 1; i <= 10; i++)
    {
        if (a.minn[p1] > b.minn[p2])
            temp.minn[i] = a.minn[p1++];
        else
            temp.minn[i] = b.minn[p2++];
    }
    return temp;
}

void pushup(int o)
{
    e[o] = hebing(e[o * 2], e[o * 2 + 1]);
}

void color(int o, int v)
{
    tag[o] += v;
    for (int i = 1; i <= 10; i++)
        if (e[o].minn[i])
        e[o].minn[i] += v;
}

void pushdown(int o)
{
    if (tag[o])
    {
        color(o * 2, tag[o]);
        color(o * 2 + 1, tag[o]);
        tag[o] = 0;
    }
}

void build(int o, int l, int r)
{
    if (l == r)
    {
        scanf("%d", &e[o].minn[1]);
        return;
    }
    int mid = (l + r) >> 1;
    build(o * 2, l, mid);
    build(o * 2 + 1, mid + 1, r);
    pushup(o); 
}

void update(int o, int l, int r, int x, int y, int v)
{
    if (x <= l && r <= y)
    {
        color(o, v);
        return;
    }
    pushdown(o);
    int mid = (l + r) >> 1;
    if (x <= mid)
        update(o * 2, l, mid, x, y, v);
    if (y > mid)
        update(o * 2 + 1, mid + 1, r, x, y, v);
    pushup(o);
}

node query(int o, int l, int r, int x, int y)
{
    if (x <= l && r <= y)
        return e[o];
    pushdown(o);    
    int mid = (l + r) >> 1;
    node temp;
    bool flag = false;
    if (x <= mid)
    {
        if (!flag)
            temp = query(o * 2, l, mid, x, y);
        else
            temp = hebing(temp, query(o * 2, l, mid, x, y));
        flag = 1;
    }
    if (y > mid)
    {
        if (!flag)
            temp = query(o * 2 + 1, mid + 1, r, x, y);
        else
            temp = hebing(temp, query(o * 2 + 1, mid + 1, r, x, y));
    }
    return temp;
}

int main()
{
    scanf("%d%d", &n, &m);
    build(1, 1, n);
    for (int i = 1; i <= m; i++)
    {
        int op, l, r, k;
        scanf("%d%d%d%d", &op, &l, &r, &k);
        if (op == 0)
        {
            if (r - l + 1 < k)
                printf("-1\n");
            else
                printf("%d\n", query(1, 1, n, l, r).minn[k]);
        }
        else
            update(1, 1, n, l, r, k);
    }

    return 0;
}