YBTOJ:向量问题(线段树分治、凸包)
生活随笔
收集整理的這篇文章主要介紹了
YBTOJ:向量问题(线段树分治、凸包)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 題目描述
- 數據范圍
- 解析
- 代碼
題目描述
你要維護一個向量集合,支持以下操作:
插入一個向量 。
刪除插入的第 x 個向量。
查詢當前集合與(x,y)(x,y)(x,y) 點積的最大值是多少。如果當前是空集輸出0。
數據范圍
n<=2e5,x、y∈[1,2e6]n<=2e5,x、y∈[1,2e6]n<=2e5,x、y∈[1,2e6]
解析
考慮作當前向量的垂線,該線自上而下平移截得的第一個向量對應的點就是答案
如果本題沒有刪除操作,可以利用一個凸包來維護
但是如何支持刪除呢?
考慮離線,對詢問時間維護一個線段樹
那么每個向量都有一個對應的有效區間
把該向量按照區間修改的方式加到線段樹上,對每個線段樹節點維護一個凸包
詢問是從葉節點一直往上走,對每一個節點的凸包二分找到切點一直更新答案
代碼
#include<bits/stdc++.h> using namespace std; const int N=2e5+100; const int M=2e6+100; #define ll long long ll read(){ll x=0,f=1;char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();};while(isdigit(c)){x=x*10+c-'0';c=getchar();};return x*f; } int n,m; struct node{ll x,y;int id;bool operator < (const node o){if(x!=o.x) return x<o.x;return y<o.y;} }p[N],ask[N]; int num,ans[N],cnt; #define mid ((l+r)>>1) #define ls (k<<1) #define rs (k<<1|1) #define ed (tr[k].size()-1) vector<int>tr[N<<2]; void add(int k,int x){while(tr[k].size()>1&&(p[tr[k][ed]].y-p[tr[k][ed-1]].y)*(p[x].x-p[tr[k][ed]].x)<=(p[x].y-p[tr[k][ed]].y)*(p[tr[k][ed]].x-p[tr[k][ed-1]].x)) tr[k].pop_back();tr[k].push_back(x); } void insert(int k,int l,int r,int x,int y,int o){//printf("insert:l=%d r=%d x=%d y=%d o=%d mid=%d %d %d\n",l,r,x,y,o,mid,x<=mid,y>mid);if(x<=l&&r<=y){//printf(" add:l=%d r=%d o=%d\n",l,r,o);add(k,o);return;}if(x<=mid) insert(ls,l,mid,x,y,o);if(y>mid) insert(rs,mid+1,r,x,y,o); } int find(int k,ll x,ll y){//printf(" k=%d find: siz=%d\n",k,tr[k].size());//for(int i=0;i<tr[k].size();i++) printf(" (%lld %lld)",p[tr[k][i]].x,p[tr[k][i]].y);//printf("\n");if(!tr[k].size()) return -1;else if(tr[k].size()==1||(p[tr[k][ed]].y-p[tr[k][ed-1]].y)*y>=-x*(p[tr[k][ed]].x-p[tr[k][ed-1]].x)) return tr[k][ed];int l=0,r=ed;while(l<r){int o=(l+r)>>1;if(o==ed||(p[tr[k][o+1]].y-p[tr[k][o]].y)*y<=-x*(p[tr[k][o+1]].x-p[tr[k][o]].x)) r=o;else l=o+1;//printf(" o=%d l=%d r=%d\n",o,l,r);}return tr[k][l]; } ll query(int k,int l,int r,int o,ll x,ll y){//printf("k=%d l=%d r=%d x=%lld y=%lld\n",k,l,r,x,y);int pl=find(k,x,y);ll res=pl==-1?0:x*p[pl].x+y*p[pl].y;if(l==r) return res;if(o<=mid) res=max(res,query(ls,l,mid,o,x,y));else res=max(res,query(rs,mid+1,r,o,x,y));return res; } int st[N],eed[N]; int main(){n=read(); // for(int i=1;i<=100;i++) tr[i].resize(10);for(int i=1;i<=n;i++){int f=read();if(f==1){int x=read(),y=read();//printf("%d %d %d\n",f,x,y);p[++cnt]=(node){x,y,cnt};st[cnt]=i;eed[cnt]=n;}else if(f==2){int x=read();eed[x]=i-1;//printf("%d %d\n",f,x);}else{int x=read(),y=read();//printf("%d %d %d\n",f,x,y);ask[++num]=(node){x,y,i};}}sort(p+1,p+1+cnt);for(int i=1;i<=cnt;i++){//printf("i=%d l=%d r=%d\n",i,st[p[i].id],eed[p[i].id]);insert(1,1,n,st[p[i].id],eed[p[i].id],i);}for(int i=1;i<=num;i++){printf("%lld\n",query(1,1,n,ask[i].id,ask[i].x,ask[i].y));}return 0; } /* 5 3 84040 650026 3 702678 199950 1 826333 497249 1 133580 956915 3 36119 655069 */總結
以上是生活随笔為你收集整理的YBTOJ:向量问题(线段树分治、凸包)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: YBTOJ洛谷P1407:稳定婚姻(强连
- 下一篇: YBTOJ:圈套问题(分治法、鸽笼原理)