日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

YBTOJ:向量问题(线段树分治、凸包)

發布時間:2023/12/3 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 YBTOJ:向量问题(线段树分治、凸包) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 題目描述
    • 數據范圍
  • 解析
  • 代碼

題目描述

你要維護一個向量集合,支持以下操作:

插入一個向量 。
刪除插入的第 x 個向量。
查詢當前集合與(x,y)(x,y)(x,y) 點積的最大值是多少。如果當前是空集輸出0。

數據范圍

n<=2e5,x、y∈[1,2e6]n<=2e5,x、y∈[1,2e6]n<=2e5,xy[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:向量问题(线段树分治、凸包)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。