链接: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;
}
/*样例区
*/
//------------------------------------------------------------
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/280039.html