BZOJ3165 : [Heoi2013]Segment
建立线段树,每个节点维护该区间内的最优线段。
插入线段时,在线段树上分裂成$O(\log n)$棵子树,若与当前点的最优线段不相交,那么取较优的,否则暴力递归子树。
查询时在叶子到根路径上所有点的最优线段中取个最优的即可。
时间复杂度$O(n\log^2n)$。
#include<cstdio> #include<cmath> #include<algorithm> #define N 39989 using namespace std; struct Seg{ double k,b; Seg(){} Seg(int x0,int y0,int x1,int y1){if(x0==x1)k=0,b=max(y0,y1);else k=1.0*(y0-y1)/(x0-x1),b=-k*x0+y0;} double gety(int x){return k*x+b;} }s[100010]; int m,op,cnt,X0,Y0,X1,Y1,ans,v[131000]; inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';} inline int sig(double x){return fabs(x)<1e-8?0:(x>0?1:-1);} void ins(int x,int a,int b,int c,int d,int p){ if(c<=a&&b<=d){ if(sig(s[p].gety(a)-s[v[x]].gety(a))>0&&sig(s[p].gety(b)-s[v[x]].gety(b))>0){v[x]=p;return;} if(sig(s[p].gety(a)-s[v[x]].gety(a))<=0&&sig(s[p].gety(b)-s[v[x]].gety(b))<=0)return; if(a==b)return; } int mid=(a+b)>>1; if(c<=mid)ins(x<<1,a,mid,c,d,p); if(d>mid)ins(x<<1|1,mid+1,b,c,d,p); } void ask(int x,int a,int b,int c){ if(sig(s[ans].gety(c)-s[v[x]].gety(c))<0)ans=v[x]; else if(!sig(s[ans].gety(c)-s[v[x]].gety(c))&&ans>v[x])ans=v[x]; if(a==b)return; int mid=(a+b)>>1; c<=mid?ask(x<<1,a,mid,c):ask(x<<1|1,mid+1,b,c); } int main(){ s[0].b=-1; read(m); while(m--){ read(op); if(!op){ read(X0),X0=(X0+ans-1)%39989+1; ans=0,ask(1,1,N,X0); printf("%d\n",ans); }else{ read(X0),read(Y0),read(X1),read(Y1); X0=(X0+ans-1)%39989+1,Y0=(Y0+ans-1)%1000000000+1; X1=(X1+ans-1)%39989+1,Y1=(Y1+ans-1)%1000000000+1; s[++cnt]=Seg(X0,Y0,X1,Y1); if(X0>X1)swap(X0,X1); ins(1,1,N,X0,X1,cnt); } } return 0; }