# 李超线段树

codechef NOV17 POLY

Lemma: Polynomial $y=x^3+ax^2+bx+c$ has at most one root greater than $k=\sqrt{\max(|b|,|c|)}+2$.

Proof: Let $u\geq v >k\geq w$ to be the roots of $y$. Then $y=(x-u)(x-v)(x-w)$ so $b=uv+uw+vw$, $c=-uvw$. Since $u,v>\sqrt {|c|}$ it holds that $|w|<1$. Thus $b=uv+w(u+v)> uv-(u+v)=(u-1)(v-1)-1$. But since $u,v>\sqrt {|b|} + 2$ we have $b> (\sqrt {|b|} + 1)^2-1=|b|+2\sqrt {|b|}>b$ which is contradiction.

于是在t>=350的情况下，三次函数最多有一个交，用李超线段树维护即可

#include <bits/stdc++.h>
#define LL long long
using namespace std;

int cnt,n,Q;
LL f[100001][4],res[1001];

LL calc(LL tar,int po){
return(f[po][0]+f[po][1]*tar+f[po][2]*tar*tar+f[po][3]*tar*tar*tar);
}

struct treenode{
int lc,rc,l,r,lab;
}tr[3000001];

void build(int l,int r){
tr[++cnt].l=l;tr[cnt].r=r;tr[cnt].lab=1;
if (l==r) return;

int mid=(l+r)>>1,t=cnt;
tr[t].lc=cnt+1;
build(l,mid);
tr[t].rc=cnt+1;
build(mid+1,r);
}

void ins(int po,int num){
if (tr[po].l==tr[po].r){
if (calc(tr[po].l,num)<calc(tr[po].l,tr[po].lab))
tr[po].lab=num;
return;
}

int mid=(tr[po].l+tr[po].r)>>1,l=tr[po].l,r=tr[po].r;
if (calc(mid,num)<calc(mid,tr[po].lab)){
int t=tr[po].lab;tr[po].lab=num;
if (calc(l,num)>calc(l,t))
ins(tr[po].lc,t);
if (calc(r,num)>calc(r,t))
ins(tr[po].rc,t);
}else{
if (calc(l,num)<calc(l,tr[po].lab))
ins(tr[po].lc,num);
if (calc(r,num)<calc(r,tr[po].lab))
ins(tr[po].rc,num);
}
}

LL que(int po,int tar){
if (tr[po].l==tr[po].r)
return(calc(tr[po].l,tr[po].lab));

LL ret=calc(tar,tr[po].lab);
int mid=(tr[po].l+tr[po].r)>>1;
if (tar<=mid)
ret=min(ret,que(tr[po].lc,tar));else
ret=min(ret,que(tr[po].rc,tar));
return(ret);
}

int main(){
int T;
scanf("%d",&T);
while (T--){
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%lld%lld%lld%lld",&f[i][0],&f[i][1],&f[i][2],&f[i][3]);
for (int i=1;i<=350;i++){
res[i]=calc(i,1);
for (int j=2;j<=n;j++)
res[i]=min(res[i],calc(i,j));
}

for (int i=1;i<=cnt;i++) tr[i].lc=tr[i].rc=tr[i].lab=0;
cnt=0;
build(351,100000);
for (int i=2;i<=n;i++)
ins(1,i);
scanf("%d",&Q);
while (Q--){
int t;
scanf("%d",&t);
if (t<=350) printf("%lld\n",res[t]);else
printf("%lld\n",que(1,t));
}
}
}

-------------------------------------------------------------------------

codechef MAY17 KILLER

posted @ 2018-02-13 16:32 z1j1n1 阅读(...) 评论(...) 编辑 收藏