小睿睿的疑惑
小睿睿的疑惑
https://ac.nowcoder.com/acm/contest/6944/E
分析
看完题,首先这绝对是一个DP题
我们设
Height[]表示高度Cost[]表示花费DP[]表示以当前点为截至点的花费最小值Pre[]表示花费的前缀和
算法一
那么DP方程:
那么我们就得到了一个的转移方程式
算法二
我们发现,对于每次的修改,需要的只是最后一次从转移到
的最小值
那么我们考虑由这个性质来维护
当我们把位置上的值改为
时
若要转移到位置
由转移式:
那么我们设
A[i]=-2*Height[i]B[i]=Height[i]*Height[i]-Pre[i]+DP[i]Loc=y
我们发现这一次转移的最小值就是的最小值
所以,我们预处理出A[]和B[]即可,将A[]看作斜率,B[]看作截距
这个就可以用权值上的李超线段树维护了
以每个数组下标建立权值可持久化李超线段树即可维护
时间复杂度:
代码
//Newcoder 6944 E
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#define LL long long
#define Cl(X,Y) memset((X),(Y),sizeof(X))
#define FOR(i,A,B) for(LL i=A;i<=B;i++)
#define BOR(i,A,B) for(LL i=A;i>=B;i--)
#define Lowbit(X) (X & (-X))
#define INF 0x3f3f3f3f3f3f3f3f
#define Rson (X<<1|1)
#define Lson (X<<1)
using namespace std;
const LL MaxN=1e5+10,MaxM=1e6+10;
LL Map[MaxN<<5];
LL Height[MaxN],DP[MaxN],Pre[MaxN];
LL Cost[MaxN],A[MaxN],B[MaxN]={INF};
LL Root[MaxN],Child[MaxN<<5][2];
LL Total,Test,Loc,Last,u,v,w,Cnt;
inline void File() {
freopen(".in","r",stdin);
freopen(".out","w",stdout);
}
inline void Copy(LL Res,LL New) { Child[Res][0]=Child[New][0]; Child[Res][1]=Child[New][1]; Map[Res]=Map[New]; }
inline LL Calc(LL X,LL Y) { return X*A[Y]+B[Y]; }
inline void Update(LL New,LL &Pre,LL L,LL R,LL Temp) {
Pre=++Cnt;
Copy(Pre,New);
if(L==R) { if(Calc(L,Temp)<Calc(L,Map[Pre])) Map[Pre]=Temp; return; }
LL Mid=(L+R)>>1;
if(Calc(Mid,Temp)<Calc(Mid,Map[Pre])) swap(Temp,Map[Pre]);
if(Calc(L,Temp)<Calc(L,Map[Pre])) Update(Child[New][0],Child[Pre][0],L,Mid,Temp);
else if(Calc(R,Temp)<Calc(R,Map[Pre])) Update(Child[New][1],Child[Pre][1],Mid+1,R,Temp);
}
inline LL Get(LL New,LL L,LL R) {
if(L==R) { return Calc(Loc,Map[New]); }
LL Mid=(L+R)>>1,Res=INF;
Res=min(Res,Calc(Loc,Map[New]));
if(Loc<=Mid) { Res=min(Res,Get(Child[New][0],L,Mid)); }
else { Res=min(Res,Get(Child[New][1],Mid+1,R)); }
return Res;
}
signed main() {
// File();
ios::sync_with_stdio(false);
cin>>Total>>Test;
FOR(i,1,Total) cin>>Height[i];
FOR(i,1,Total) cin>>Cost[i],Pre[i]=Pre[i-1]+Cost[i];
A[1]=-2*Height[1];
B[1]=Height[1]*Height[1]-Pre[1];
Update(Root[0],Root[1],0,MaxM,1);
FOR(i,2,Total) {
Loc=Height[i];
DP[i]=Height[i]*Height[i]+Pre[i-1]+Get(Root[i-1],0,MaxM);
A[i]=-2*Height[i];
B[i]=DP[i]+Height[i]*Height[i]-Pre[i];
Update(Root[i-1],Root[i],0,MaxM,i);
}
while(Test--) {
cin>>u>>v;
u=((u^Last)%Total+Total)%Total+1;
if(u==1) { cout<<(Last=0)<<endl; }
else {
Loc=v;
cout<<(Last=Get(Root[u-1],0,MaxM)+v*v+Pre[u-1])<<endl;
}
}
// fclose(stdin);
// fclose(stdout);
system("pause");
return 0;
}
查看9道真题和解析
