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行,每行输出一个浮点数,保留两位小数,表示所求的最大值。
备注:
输入只有整形
分析
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; } /*样例区 */ //------------------------------------------------------------