BZOJ4311 向量(線段樹分治,斜率優化)

2022-03-20 05:07:49 字數 1659 閱讀 8295

bzoj

先考慮對於給定的向量集,如何求解和當前向量的最大內積。

設當前向量\((x,y)\),有兩個不同的向量\((u1,v1),(u2,v2)\),並且\(u1>u2\)

假設第乙個向量的結果優於第二個。

\(xu1+yv1>xu2+yv2\)

移項可以得到

\(x(u1-u2)>y(v2-v1)\)

所以\(x/y>(v2-v1)/(u1-u2)\)

也就是\(-x/y>(v1-v2)/(u1-u2)\)

右邊是乙個斜率,左邊是詢問向量和原點構成的斜率的垂線。

所以維護乙個上凸殼,每次在上面二分(三分)一下就好了

時間複雜度\(o(nlog^2n)\)

按照之前聽到的方法,因為每次詢問如果排序之後,二分的結果是單調的,

所以暴力掃一遍就好。時間複雜度\(o(nlogn)\)

我寫的是兩個log的。

#include#include#include#include#include#include#include#include#include#includeusing namespace std;

#define ll long long

#define lson (now<<1)

#define rson (now<<1|1)

#define max 200200

inline int read()

struct vectorp[max],q[max];

bool cmp(vector a,vector b)

int mid=(l+r)>>1;

if(l<=mid)modify(lson,l,mid,l,r,id);

if(r>mid)modify(rson,mid+1,r,l,r,id);

}ll inner(vector a,vector b)

ll cross(vector a,vector b,vector c)

vector s[max];

int top;

ll query(int id)

for(int i=l;i<=r;++i)ret=max(ret,inner(q[id],s[i]));

return ret;

}void work(int now,int l,int r)

for(int i=l;i<=r;++i)ans[i]=max(ans[i],query(i));

if(l==r)return;int mid=(l+r)>>1;

}void divide(int now,int l,int r)

int main()

; }

else if(opt==2)

p[read()].r=tim;

else

; }

} for(int i=1;i<=tot;++i)if(p[i].r==-1)p[i].r=tim;

for(int i=1;i<=tot;++i)if(p[i].l<=p[i].r)modify(1,1,tim,p[i].l,p[i].r,i);

divide(1,1,tim);

for(int i=1;i<=tim;++i)printf("%lld\n",ans[i]);

return 0;

}

bzoj4311 向量(線段樹分治 凸包)

傳送門 題意 支援插入乙個向量,刪去某乙個現有的向量,查詢現有的所有向量與給出的乙個向量的點積的最大值。思路 考慮線段樹分治。先對於每個向量處理出其有效時間放到線段樹上面,然後考慮查詢 對於兩個已有的向量 u1 v1 u 1,v 1 u1 v 1 和 u2 v2 u 2,v 2 u2 v 2 假設給...

bzoj4311向量(線段樹分治 斜率優化)

第二道線段樹分治。首先設當前向量是 x,y 剩餘有兩個不同的向量 u1,v1 u2,v2 假設u1 u2,則移項可得,若 u1,v1 優於 u2,v2 則 x y v1 v2 u1 u2 然後維護上凸殼後進行三分即可,複雜度o nlog2n 如果將詢問排序掃一遍,可以優化到o nlogn 當然我沒寫...

線段樹分治

動態圖聯通性 可離線 loj121 給你一張無向圖,你要支援如下操作 1 刪除一條邊 2 加入一條邊 3 查詢某兩個點對間是否聯通 離線做法 線段樹分治 口胡做法 把操作的順序當做時間。每條邊維護乙個存活區間,代表這條邊在這個時間區間裡面活著。對時間軸建立一顆線段樹,從線段樹根開始dfs。進入乙個子...