BZOJ 3922 Karin的弹幕 线段树

题目大意

给出一个序列,支持单点修改,每次查询一个位置成等差数列中所有数的最大值。

思路

等差数列如果公差很大的话,那么整个数列中的数并不会很多;但是如果公差很小,我们就可以用线段树来乱搞。具体方法是对于每个公差维护一个线段树,按照对这个公差取模的值来进行划分。这样询问的时候就在一块了。
具体看代码。

CODE

#define _CRT_SECURE_NO_WARNINGS

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 70010
#define INF 0x3f3f3f3f
using namespace std;
#define LEFT (pos << 1)
#define RIGHT (pos << 1|1)

int cnt, asks;
int src[MAX];

int tree[55][MAX << 2];
int shine[55][MAX];
int _src[55][MAX];
int _end[55][55];

void BuildTree(int tree[], int src[], int l, int r, int pos)
{
    if(l == r) {
        tree[pos] = src[l];
        return ;
    }
    int mid = (l + r) >> 1;
    BuildTree(tree, src, l, mid, LEFT);
    BuildTree(tree, src, mid + 1, r, RIGHT);
    tree[pos] = max(tree[LEFT], tree[RIGHT]);
}

void Modify(int tree[], int l, int r, int x, int c, int pos)
{
    if(l == r) {
        tree[pos] += c;
        return ;
    }
    int mid = (l + r) >> 1;
    if(x <= mid)    Modify(tree, l, mid, x, c, LEFT);
    else    Modify(tree, mid + 1, r, x, c, RIGHT);
    tree[pos] = max(tree[LEFT], tree[RIGHT]);
}

int Ask(int tree[], int l, int r, int x, int y, int pos)
{
    if(l == x && y == r)
        return tree[pos];
    int mid = (l + r) >> 1;
    if(y <= mid)    return Ask(tree, l, mid, x, y, LEFT);
    if(x > mid)     return Ask(tree, mid + 1, r, x, y, RIGHT);
    int left = Ask(tree, l, mid, x, mid, LEFT);
    int right = Ask(tree, mid + 1, r, mid + 1, y, RIGHT);
    return max(left, right);
}

int main()
{
    cin >> cnt;
    for(int i = 1; i <= cnt; ++i)
        scanf("%d", &src[i]);
    int range = min(5, cnt);
    for(int i = 1; i <= range; ++i) {
        int now = 0;
        for(int j = 1; j <= i; ++j) {
            for(int k = j; k <= cnt; k += i) {
                shine[i][k] = ++now;
                _src[i][now] = src[k];
            }
            _end[i][j] = now;
        }
        BuildTree(tree[i], _src[i], 1, cnt, 1);
    }
    cin >> asks;
    for(int flag, x, y, i = 1; i <= asks; ++i) {
        scanf("%d%d%d", &flag, &x, &y);
        if(!flag) {
            src[x] += y;
            for(int j = 1; j <= range; ++j)
                Modify(tree[j], 1, cnt, shine[j][x], y, 1);
        }
        else {
            if(y <= range)
                printf("%d\n", Ask(tree[y], 1, cnt, shine[y][x], _end[y][x % y ? x % y:y], 1));
            else {
                int ans = -INF;
                for(int j = x; j <= cnt; j += y)
                    ans = max(ans, src[j]);
                printf("%d\n", ans);
            }
        }
    }
    return 0;
}

不知道为什么,如果把_end数组的第二维开成MAX就会RE。
哪位神犇知道告诉我一下啊。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值