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;
}

  

posted @ 2015-10-08 19:25  Claris  阅读(548)  评论(1编辑  收藏  举报