李超樹——由一次NOIP模擬賽引出的車禍記

李超樹是什麼?

李超樹是一種用線段樹來維護直線的一種方法,因爲是集訓隊隊員李超在論文中提到,所以尊稱爲李超樹。

這是一次怎樣的NOIP模擬賽?

這是一次關於生死的考驗.
所以我十分認真對待。
第一題如此:
在這裏插入圖片描述
我一下子就想到了李超樹,只是把直線換成拋物線而已嘛~
所以就開始着手。。
由於第一次打李超樹,有點尷尬。
1個小時調對樣例…
3個小時拍完…
然後很尷尬的發現極限數據我跑了23秒!!!
心態沒了…
不想打比賽了…

4000+的程序,也許只有暴力分…

很尷尬我發現它跑到了90分…

代碼如下

(博主很懶,沒有打樸素的李超樹)
代碼很醜,情況很多
心態很崩
猛地發現這樣分類好像保證不了複雜度

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#define LL long long
using namespace std;

const LL maxn=5*1e5+10;
const LL maxq=5*1e5+10;
const LL maxX=32323+10;
const LL XXX=-32324-100;

struct root{double x,x1;};
struct Moon{
	LL a,b;
}f[2*maxX*4];

LL a[maxn],b[maxn];
LL x[maxq];
LL minx,maxx;
LL N,Q;

inline LL read(){
    LL d=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
    return d*f;
}

root cro(LL a1,LL b1,LL a2,LL b2,LL liml,LL limr){
	LL a=a1-a2,b=b1-b2;
	root R;
	if(a==0){
		R.x=0;
		R.x1=XXX;
		if(R.x>limr||R.x<liml) R.x=XXX;
	}else{
		LL delta=b*b;
		if(delta==0){
			R.x=(-b+sqrt(delta+0.0)+0.0)/(2*a+0.0);
			R.x1=XXX;
			if(R.x>limr||R.x<liml) R.x=XXX;
		}else{
			double R1=(-b+sqrt(delta+0.0)+0.0)/(2*a+0.0);
			double R2=(-b-sqrt(delta+0.0)+0.0)/(2*a+0.0);
			if(R1>R2) swap(R1,R2);
			R.x=R1,R.x1=R2;
			while(R.x!=XXX&&(R.x>=limr||R.x<=liml)) 
				R.x=R.x1,R.x1=XXX;
		}
	}
	return R;
}

LL val(LL a,LL b,LL x){
	return a*x*x+b*x;
}


void add(LL v,LL l,LL r,LL a,LL b,LL L,LL R){
	if(f[v].a<XXX){
		f[v].a=a,f[v].b=b;
		return;
	}
	if(f[v].a==a&&f[v].b==b) return;
	root p=cro(a,b,f[v].a,f[v].b,l,r);
	if(p.x==XXX){
		int ll=l;
		while(ll<r&&val(a,b,ll)==val(f[v].a,f[v].b,ll)) ++ll;
		if(val(a,b,ll)>val(f[v].a,f[v].b,ll)) f[v].a=a,f[v].b=b;
		return;
	}else{
		LL nl,nr;
		if(p.x1==XXX){
			//交點只有一個 
			
			int ll=l;
			while(ll<r&&val(a,b,ll)==val(f[v].a,f[v].b,ll)) ++ll;
			if(val(a,b,ll)>val(f[v].a,f[v].b,ll))
				nl=l,nr=floor(p.x);
			else nl=ceil(p.x),nr=r;
			ll=r;
			while(ll>l&&val(a,b,ll)==val(f[v].a,f[v].b,ll)) --ll;
			if(val(a,b,ll)>val(f[v].a,f[v].b,ll)&&nl==l&&nr==floor(p.x)){
				f[v].a=a,f[v].b=b;
				return;
			}
			if(val(a,b,ll)<val(f[v].a,f[v].b,ll)&&nl==ceil(p.x)&&nr==r) return;
			int mid=((l+r)%2!=0)?(l+r-1)/2:(l+r)/2;
			if(nr<=mid) add(v*2,l,mid,a,b,nl,nr);
			else if(nl>mid) add(v*2+1,mid+1,r,a,b,nl,nr);
			else{
				add(v*2,l,mid,a,b,nl,mid);
				add(v*2+1,mid+1,r,a,b,mid+1,nr);	
			}
		}else{
			bool flag=0;
			nl=ceil(p.x),nr=floor(p.x1);
			int ll=nl;
			while(ll<nr&&val(a,b,ll)==val(f[v].a,f[v].b,ll)) ++ll;
			if(val(a,b,ll)==val(f[v].a,f[v].b,ll)){
				ll=nl;
				while(ll>l&&val(a,b,ll)==val(f[v].a,f[v].b,ll)) --ll;
				if(val(a,b,ll)==val(f[v].a,f[v].b,ll)){
					ll=nr;
					while(ll<r&&val(a,b,ll)==val(f[v].a,f[v].b,ll)) ++ll;
				}
				if(val(a,b,ll)>val(f[v].a,f[v].b,ll)) flag=1;
			}else if(val(a,b,ll)<val(f[v].a,f[v].b,ll)) flag=1;
			if(flag){
				// two side
				int nl1,nr1;
				nl1=l,nr1=nl-1;
				int mid=((l+r)%2!=0)?(l+r-1)/2:(l+r)/2;
				if(nr1<=mid) add(v*2,l,mid,a,b,nl1,nr1);
				else if(nl1>mid) add(v*2+1,mid+1,r,a,b,nl1,nr1);
				else{
					add(v*2,l,mid,a,b,nl1,mid);
					add(v*2+1,mid+1,r,a,b,mid+1,nr1);	
				}
				nl1=nr+1,nr1=r;
				mid=((l+r)%2!=0)?(l+r-1)/2:(l+r)/2;
				if(nr1<=mid) add(v*2,l,mid,a,b,nl1,nr1);
				else if(nl1>mid) add(v*2+1,mid+1,r,a,b,nl1,nr1);
				else{
					add(v*2,l,mid,a,b,nl1,mid);
					add(v*2+1,mid+1,r,a,b,mid+1,nr1);	
				}
			}else{
				//one side
				int mid=((l+r)%2!=0)?(l+r-1)/2:(l+r)/2;
				if(nr<=mid) add(v*2,l,mid,a,b,nl,nr);
				else if(nl>mid) add(v*2+1,mid+1,r,a,b,nl,nr);
				else{
					add(v*2,l,mid,a,b,nl,mid);
					add(v*2+1,mid+1,r,a,b,mid+1,nr);	
				}
			}
		}
	}
	if(l==r) return;
}

LL query(LL v,LL l,LL r,LL x,LL s){
	if(f[v].a>XXX)s=max(s,val(f[v].a,f[v].b,x));
	if(l==r) return s;
	int mid=((l+r)%2!=0)?(l+r-1)/2:(l+r)/2;
	if(x<=mid) return query(v*2,l,mid,x,s);
	else return query(v*2+1,mid+1,r,x,s);
}

int main(){
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
	N=read();
	Q=read();
	LL i,j;
	
	for (i=1;i<=N;++i)
		a[i]=read(),b[i]=read();
	memset(f,128,sizeof(f));
	minx=1e18;
	maxx=-1e18;
	for (i=1;i<=Q;++i){
		x[i]=read();
		minx=min(x[i],minx);
		maxx=max(x[i],maxx);
	}
	
	for (i=1;i<=N;++i)
		add(1,minx,maxx,a[i],b[i],minx,maxx);
	
	for (i=1;i<=Q;++i)
		printf("%lld\n",query(1,minx,maxx,x[i],-1e18));
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章