1027 求最大值 线段树维护区间内斜率的最大值

 链接:https://ac.nowcoder.com/acm/contest/26896/1027
来源:牛客网

题目描述

给出一个序列,你的任务是求每次操作之后序列中 (a[j]-a[i])/(j-i)【1<=i<j<=n】的最大值。
操作次数有Q次,每次操作需要将位子p处的数字变成y.

输入描述:

本题包含多组输入,每组输入第一行一个数字n,表示序列的长度。
然后接下来一行输入n个数,表示原先序列的样子。
再接下来一行一个数字Q,表示需要进行的操作的次数。
最后Q行每行两个元素p,y,表示本操作需要将位子p处的数字变成y.
数据范围:
3<=n<=200000
1<=Q<=200000
-1000000000<=a[i]<=1000000000

输出描述:

每组数据输出Q行,每行输出一个浮点数,保留两位小数,表示所求的最大值。
示例1

输入

复制
5
2 4 6 8 10
2
2 5
4 9

输出

复制
3.00
3.00

说明

第一次操作之后的序列变成:2 5 6 8 10
第二次操作之后的序列变成:2 5 6 9 10

备注:

输入只有整形

分析

a[y] - a[x] / (y - x) 就是求斜率最大值。观察可得,斜率最大值只会在相邻的两个点之间产生,所以只要用线段树,维护区间内所有节点的差值的最大值就可以了。

考虑到对某个点增加一个量,只会影响到当前点到前一个点 和 当前点到后一个点的斜率。

修改的时候,只要将当前位置的线段树上的点 + 差值 ,当前该点的下一个点减去差值,就是斜率的变化了。

由于维护的是斜率,而的一个点前面没有值,差值自然是的一个节点的权值,但这并不是斜率,所以对于第一个点,不用维护。

如果是最后一个点,那最后一个点下一个点也没有值,所以不用维护。

//-------------------------代码----------------------------

//#define int ll
const int N = 2e5+10;
int n,m;

struct node {
    int l,r;
    double mx;
} tr[N<<2];
double a[N];

void push_up(int u) {
    tr[u].mx = max(tr[ul].mx ,tr[ur].mx);
}

void build(int u,int l,int r) {
    tr[u] = {l,r};
    if(l == r) {tr[u].mx = a[l] - a[l-1]; rt;}build(ul,l,tr_mid);build(ur,tr_mid+1,r);
    push_up(u);
}
void modify(int u,int x,int c) {
    if(x == tr[u].l && tr[u].r ==x) {
        tr[u].mx += c;rt;
    }
    if(x <= tr_mid) modify(ul,x,c);
    else modify(ur,x,c);
    push_up(u);
}

void solve()
{
    fo(i,1,n) cin>>a[i];
    build(1,2,n);
    
    cin>>m;
    while(m --) {
        int p;double y;cin>>p>>y;
        if(p>1)modify(1,p,y-a[p]);
        if(p<n)modify(1,p+1,a[p]-y);
        a[p] = y;
       cout<<fixed<<setprecision(2)<<tr[1].mx<<endl;;
    }
}
void main_init() {}
signed main(){
    AC();clapping();TLE;
    main_init();
    while(cin>>n)
//  while(cin>>n>>m,n,m)
//    int t;cin>>t;while(t -- )
    solve();
//    {solve(); }
    return 0;
}

/*样例区


*/

//------------------------------------------------------------

 

posted @ 2022-08-12 03:17  er007  阅读(67)  评论(0编辑  收藏  举报