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。進入乙個子...