BZOJ 3533 [SDOI2014]向量集 (線段樹維護凸包)

題面:BZOJ傳送門 洛谷傳送門

容易想到這樣一個結論

把每次插入向量$(z,w)$改爲在座標系內插入一個點$(z,w)$,並對這些點建出凸包。

每次詢問向量$(x,y)$的答案,設一條直線$l$垂直於$(x,y)$,用l去切所有已知向量構成的凸包,第一個切到的點就是最優解,根據$y$的正負來決定是從上面切還是下面切

簡單證明一下,向量點積相當於向量$(z,w)$在$(x,y)$上的投影*$|(x,y)|$,所以要找在$(x,y)$方向上最長的向量。

我們對向量$(x,y)$所在的直線作垂線,假設垂線經過點$(z,w)$,並交$y$軸於一點$p$,那麼$p$點的縱座標*向量$(x,y)$與$y$軸的夾角就是向量$(z,w)$的投影長,爲了找最長的投影所以建凸包

然後就是維護凸包了,可題目要求強制在線,不能$CDQ$,詢問$[l,r]$區間的凸包且$x$無序,可持久化splay維護凸包?

維護可持久化凸包一般是用線段樹,線段樹每個區間都掛一個凸包,詢問$[l,r]$區間的凸包相當於區間查詢

如果保證x有序,每個新來的點在線段樹的每一層都插入,動態建出凸包。

所有詢問不會超出已知的凸包範圍!

每當線段樹的一個區間被插滿之後再建出凸包就行了。不會詢問沒建完的區間的凸包

每次在凸包上二分即可

時間$O(nlog^{2}n)$

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #define N1 400010
  5 #define dd double
  6 #define ll long long 
  7 using namespace std;
  8 
  9 const ll inf=0x3f3f3f3f3f3f3f3fll;
 10 const int zwz=1000000007;
 11 int gint()
 12 {
 13     int ret=0,fh=1;char c=getchar();
 14     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
 15     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
 16     return ret*fh;
 17 }
 18 
 19 int n,Q;
 20 ll X[N1],Y[N1];
 21 int pos[N1];//id[N1];
 22 int cmpx0(int x,int y){ if(X[x]!=X[y]) return X[x]<X[y]; else return Y[x]<Y[y];}
 23 int cmpx1(int x,int y){ if(X[x]!=X[y]) return X[x]<X[y]; else return Y[x]>Y[y];}
 24 struct OP{int x,y,l,r;}op[N1];
 25 ll ask(int i,ll x,ll y){ return X[i]*x+Y[i]*y; }
 26 
 27 struct SEG{
 28 
 29 int stk0[20][N1],stk1[20][N1],ed0[N1<<2],ed1[N1<<2],que[N1];
 30 
 31 int cmp(int a,int b,ll x,ll y)
 32 {
 33     if(!a||!b) return a+b;
 34     return (X[a]*y+Y[a]*(-x)>X[b]*y+Y[b]*(-x))?a:b;
 35 }
 36 
 37 void build0(int *s,int &tp,int l,int r)
 38 {
 39     int i,j;
 40     for(i=l;i<=r;i++) que[i-l+1]=i;
 41     sort(que+1,que+r-l+2,cmpx0);
 42     for(j=1;j<=r-l+1;j++)
 43     {
 44         i=que[j];
 45         while(tp>1&&(Y[i]-Y[s[tp-1]])*(X[s[tp]]-X[s[tp-1]])>=(Y[s[tp]]-Y[s[tp-1]])*(X[i]-X[s[tp-1]]))
 46             tp--;
 47         s[++tp]=i;
 48     }
 49 }
 50 int qup(int *s,int l,int r,int rt,ll x,ll y)
 51 {
 52     if(!ed0[rt]) build0(s,ed0[rt],l,r);
 53     if(ed0[rt]==1) return s[1];
 54     l=2,r=ed0[rt]; int mid,ans=s[1];
 55     while(l<=r)
 56     {
 57         mid=(l+r)>>1; 
 58         if(1.0*(Y[s[mid]]-Y[s[mid-1]])/(X[s[mid]]-X[s[mid-1]])>=1.0*y/x) ans=s[mid],l=mid+1;
 59         else r=mid-1;
 60     }
 61     return ans;
 62 }
 63 int qmax(int L,int R,int l,int r,int rt,int D,ll x,ll y)
 64 {
 65     if(L<=l&&r<=R) return qup(stk0[D]+l-1,l,r,rt,x,y);
 66     int mid=(l+r)>>1,ans=0,tmp;
 67     if(L<=mid) tmp=qmax(L,R,l,mid,rt<<1,D+1,x,y),ans=cmp(ans,tmp,x,y);
 68     if(R>mid) tmp=qmax(L,R,mid+1,r,rt<<1|1,D+1,x,y),ans=cmp(ans,tmp,x,y);
 69     return ans;
 70 }
 71 
 72 
 73 void build1(int *s,int &tp,int l,int r)
 74 {
 75     int i,j;
 76     for(i=l;i<=r;i++) que[i-l+1]=i;
 77     sort(que+1,que+r-l+2,cmpx1);
 78     for(j=1;j<=r-l+1;j++)
 79     {
 80         i=que[j];
 81         while(tp>1&&(Y[i]-Y[s[tp-1]])*(X[s[tp]]-X[s[tp-1]])<=(Y[s[tp]]-Y[s[tp-1]])*(X[i]-X[s[tp-1]]))
 82             tp--;
 83         s[++tp]=i;
 84     }
 85 }
 86 int qdown(int *s,int l,int r,int rt,ll x,ll y)
 87 {
 88     if(!ed1[rt]) build1(s,ed1[rt],l,r);
 89     if(ed1[rt]==1) return s[1];
 90     l=2,r=ed1[rt]; int mid,ans=s[1];
 91     while(l<=r)
 92     {
 93         mid=(l+r)>>1;
 94         if(1.0*(Y[s[mid]]-Y[s[mid-1]])/(X[s[mid]]-X[s[mid-1]])<=1.0*y/x) ans=s[mid],l=mid+1;
 95         else r=mid-1;
 96     }
 97     return ans;
 98 }
 99 int qmin(int L,int R,int l,int r,int rt,int D,ll x,ll y)
100 {
101     if(L<=l&&r<=R) return qdown(stk1[D]+l-1,l,r,rt,x,y);
102     int mid=(l+r)>>1,ans=0,tmp;
103     if(L<=mid) tmp=qmin(L,R,l,mid,rt<<1,D+1,x,y),ans=cmp(ans,tmp,x,y);
104     if(R>mid) tmp=qmin(L,R,mid+1,r,rt<<1|1,D+1,x,y),ans=cmp(ans,tmp,x,y);
105     return ans;
106 }
107 
108 }s;
109 ll ans;
110 void decode(int &x){ x=x^(ans&0x7fffffff); }
111 
112 int de;
113 int main()
114 {
115     Q=gint(); char str[10],Str[10]; scanf("%s",Str);
116     int x,y,l,r,i,j,nn=0,a; 
117     for(i=1;i<=Q;i++)
118     {
119         scanf("%s",str);
120         if(str[0]=='A'){
121             op[i].x=gint(), op[i].y=gint(); nn++; pos[i]=nn; //id[nn]=i;
122         }else{
123             op[i].x=gint(), op[i].y=gint();
124             op[i].l=gint(), op[i].r=gint();
125         }
126     }
127     for(i=1;i<=Q;i++)
128     {
129         x=op[i].x; y=op[i].y; l=op[i].l; r=op[i].r;
130         if(!l&&!r){
131             if(Str[0]!='E') decode(x), decode(y); X[pos[i]]=x; Y[pos[i]]=y;
132         }else{
133             if(Str[0]!='E') decode(x), decode(y), decode(l), decode(r);
134             if(y>0) a=s.qmax(l,r,1,nn,1,0,-y,x); 
135             else a=s.qmin(l,r,1,nn,1,0,-y,x); 
136             ans=X[a]*x+Y[a]*y;
137             printf("%lld\n",ans);
138         }
139     }
140     return 0;
141 }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章