BZOJ1568: [JSOI2008]Blue Mary开公司
可以平衡树或线段树维护斜率来做。还有一种线段树直接打标记的做法(李超线段树):线段树每个节点存一条线段作为标记,打标记时如果已有标记,则把占优区间小的那个线段下放。
#include<cstdio> #include<algorithm> #define N 50000 #define M (l+r>>1) #define P (k<<1) #define S (k<<1|1) #define L l,M,P #define R M+1,r,S #define Z \ int l=0,int r=N-1,int k=1 using namespace std; struct node{ double s,t; double val(int x){ return s*x+t; } }e[N*2],*u=e,*a[N*4]; void apply(node*s,Z){ if(!a[k])a[k]=s; else{ if(a[k]->val(M)<s->val(M)) swap(a[k],s); if(l!=r) a[k]->s<s->s?apply(s,R):apply(s,L); } } double query(int s,Z){ double v=a[k]?a[k]->val(s):0; if(l!=r) v=max(v,s<=M?query(s,L):query(s,R)); return v; } int i,m; char k[8]; double s,t; int main(){ for(scanf("%d",&m);m;--m){ scanf("%s",k); if(*k==80){ scanf("%lf%lf",&t,&s); apply(&(*u++=(node){s,t})); } else{ scanf("%d",&i); printf("%d\n",(int)query(i-1)/100); } } }
之前写的是一个奇怪的做法……
答案序列一定是个下凸壳,因此添加的等差数列与其之差是个单峰函数,可以先三分求出最值,再二分求出零点,然后用线段树,将得到的区间修改为一个等差数列。
要降低复杂度的话可以把三分和二分写到线段树里面……
#include<cstdio> #define Z \ int l=1,int r=N,int k=1 #define N 50000 #define M (l+r>>1) #define P (k<<1) #define S (k<<1|1) #define K l,r,k #define L l,M,P #define R M+1,r,S double a[N*4],b[N*4]; void devolve(Z){ if(b[k]){ a[S]=a[k]+(M-l+1)*(b[P]=b[S]=b[k]); a[P]=a[k],b[k]=0; } } double query(int s,Z){ if(l!=r){ devolve(K); return s<=M?query(s,L):query(s,R); } return a[k]; } void amend(double u,double v,int s,int t,Z){ if(s==l&&t==r) a[k]=u,b[k]=v; else{ devolve(K); if(t<=M) amend(u,v,s,t,L); else if(s>M) amend(u,v,s,t,R); else{ amend(u,v,s,M,L); amend(u+(M-s+1)*v,v,M+1,t,R); } } } double s,t; int i,j,m,r,l; char k[8]; void solve(){ scanf("%lf%lf",&s,&t); l=1,r=N; while(l!=r){ i=l+(r-l)/3; j=r-(r-l)/3; if(t*(i-j)<query(i)-query(j)) l=i+1; else r=j-1; } if(s+t*l-t>query(l)){ r=l,l=1; while(l!=r){ i=l+r>>1; if(s+t*i-t>query(i)) r=i; else l=i+1; } j=l,r=N; while(l!=r){ i=l+r+1>>1; if(s+t*i-t>query(i)) l=i; else r=i-1; } amend(s+t*j-t,t,j,l); } } int main(){ for(scanf("%d",&m);m;--m){ scanf("%s",k); if(*k==80) solve(); else{ scanf("%d",&i); printf("%d\n",(int)query(i)/100); } } }
最后吐槽一句这题啥破样例啊。