CodeChef:L-R queries(线段树 & set)

Chef has an array A of size N. His friend Chuwi playing with this array in a next way: he chooses a continuous subarray A[L..R] and finds the maximum of (A[M] - A[L]) * (A[R] - A[M]) over all values of M where L ≤ M ≤ R. Chef wants to hopple Chuwi and changes elements of his array sometimes. Please help Chuwi to solve this easy problem.

Input

The first line of the input contains an integer T denoting the number of test cases. The description of T test cases follows. The first line of each test case contains two positive integers N denoting the number of elements in Chef's array and Q denoting the number of operations performed by Chef and Chuwi. The second line contains N space-separated integers A1A2, ..., AN denoting the Chef's array. Next Q contains three integers - type = 1 L R denoting that Chuwi takes subarray A[L..R] and finds the maximum of his function. type = 2 X Y denoting that Chef changes element A[X] by Y.

 

Output

For every Chuwi's performed operation output the maximal value in a single line.

 

Constraints

  • 1 ≤ T ≤ 1000
  • 1 ≤ NQ ≤ 105
  • 1 ≤ AiY ≤ 109
  • 1 ≤ L ≤ R ≤ N
  • 1 ≤ X ≤ N
  • 1 ≤ type ≤ 2
  • Sum of N over all test cases ≤ 2*105
  • Sum of Q over all test cases ≤ 2*105

Subtasks

  • Subtask #1: (20 points) sum of N over all test cases ≤ 5*103 and sum of Q over all test cases ≤ 5*103 and TL = 1 sec
  • Subtask #2: (30 points) 1 ≤ AiY ≤ 102
  • Subtask #3: (50 points) Original constraints

 

Example

Input:
1
4 3
2 1 4 3
1 1 4
2 2 3
1 1 3

Output:
0
1

 

Explanation

Example case 1. For Chuwi's subarray [2, 1, 4, 3] there are 4 possible values of (A[M] - A[L]) * (A[R] - A[M]) - {0, -2, -2, 0} correspondingly, maximal value will be 0. After the second operation array will be [2, 3, 4, 3]. And for Chuwi's subarray [2, 3, 4] possible 3 values - {0, 1, 0}, hence answer is 1.

题意:大厨有一个长度为 N 的序列 A。他的朋友 Chuwi 在干这样的事情:选择一段连续的序列并A[L..R] 求出下式的最大值:(A[M] − A[L]) · (A[R] − A[M])其中 L ≤ M ≤ R。大厨想整一下 Chuwi,所以他会时不时地改变序列中一些元素的值。请帮Chuwi 搞定这道水题。

思路:显然这是一个开口向下的二次函数,最值在X=(A[L]+A[R])/2处取得,那么我们在所给区间内找到距离它最近的点即可。那么线段树能不能使其线段内的数都有序呢?这样子就能二分查找了,用set就行,建树的时候合并区间set应该按顺序插入减少时间消耗,同时节点存数的2倍方便查找。

# include <iostream>
# include <cstdio>
# include <algorithm>
# include <set>
# define lson l,m,id<<1
# define rson m+1,r,id<<1|1
# define inf 0x7fffffff
using namespace std;
typedef long long LL;
const int maxn = 1e5+3;
multiset<int>s[4*maxn];
int a[maxn];
void build(int l, int r, int id)
{
    s[id].clear();
    if(l==r)
    {
        s[id].insert(a[l]<<1);
        return;
    }
    int m = l+r>>1;
    build(lson);
    build(rson);
    auto it1=s[id<<1].begin();
    auto it2=s[id<<1|1].begin();
    while(it1!=s[id<<1].end() && it2!=s[id<<1|1].end())
    {
        if(*it1 <= *it2)
        {
            s[id].insert(*it1);
            ++it1;
        }
        else
        {
            s[id].insert(*it2);
            ++it2;
        }
    }
    for(;it1 != s[id<<1].end();++it1) s[id].insert(*it1);
    for(;it2 != s[id<<1|1].end();++it2) s[id].insert(*it2);
}

int query(int L, int R, int num, int l, int r, int id)
{
    if(L<=l &&R>=r)
    {
        int res = inf, ans;
        auto it = s[id].upper_bound(num);
        if(it != s[id].end())
            if(abs(*it-num) < res) ans = *it, res=abs(*it-num);
        if(it-- != s[id].begin())
            if(abs(*it-num) < res) ans = *it;
        return ans;
    }
    int m = l+r>>1, res=inf, ans;
    if(L<=m)
    {
        int tmp = query(L, R, num, lson);
        if(abs(tmp-num) < res) ans = tmp, res=abs(tmp-num);
    }
    if(R > m)
    {
        int tmp = query(L, R, num, rson);
        if(abs(tmp-num) < res) ans = tmp;
    }
    return ans;
}

void update(int pos, int num, int pre, int l, int r, int id)
{
    s[id].erase(s[id].find(pre<<1));
    s[id].insert(num<<1);
    if(l == r) return;
    int m = l+r>>1;
    if(pos<=m) update(pos, num, pre, lson);
    if(pos > m) update(pos, num, pre, rson);
}
int main()
{
    int T, n, q;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&q);
        for(int i=1; i<=n; ++i) scanf("%d",&a[i]);
        build(1,n,1);
        while(q--)
        {
            int op, l, r;
            scanf("%d%d%d",&op,&l,&r);
            if(op==1)
            {
                int big = a[l]+a[r];
                int ans = query(l,r,big,1,n,1)/2;
                printf("%lld\n",(1LL*ans-a[l])*(1LL*a[r]-ans));
            }
            else
            {
                update(l, r, a[l], 1, n, 1);
                a[l] = r;
            }
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值