题目链接:https://www.luogu.com.cn/problem/P3309
n个操作
- 在序列末尾加入一个向量(x,y)
- 询问加入的第l∼r个向量中的一个向量和(x,y)的点积最大值
强制在线,点积的定义为x1x2+y1y2
如果对于一个(x,y)对于两个(x1,y1)和(x2,y2)如果后者更大那么有
x2x+y2y>x1x+y1y⇒yx≤x2−x1y2−y1
好像和斜率有关,可以维护凸壳来做,因为y可能是负数,如果是负数的时候就要求的是下凸壳了,所以两个凸壳都要维护。
因为强制在线所以上不了传统艺能CDQ
那怎么动态维护区间凸壳,平衡树支持动态插入但不支持区间问题。所以考虑线段树,因为一个位置修改了之后就不会再修改,而且是从左往右加的,可以利用这个性质。
每次我们修改一个位置后,如果一个区间[L,R]的节点内已经插入了R−L+1个向量(也就是都插完了)的话就直接把它的两个儿子的凸壳合并起来。
然后询问的时候分成log n个区间询问的答案取最大值就好了。
合并凸壳的是用归并排序的话时间复杂度O(nlogn)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define ll long long
using namespace std;
struct point{
ll x,y;
point(ll xx=0,ll yy=0)
{x=xx;y=yy;return;}
}z;
point operator+(point x,point y)
{return point(x.x+y.x,x.y+y.y);}
point operator-(point x,point y)
{return point(x.x-y.x,x.y-y.y);}
ll operator^(point x,point y)
{return x.x*y.y-x.y*y.x;}
ll operator*(point x,point y)
{return x.x*y.x+x.y*y.y;}
bool operator<(point x,point y)
{return (x.x==y.x)?x.y<y.y:x.x<y.x;}
const ll N=4e5+10;
char pe[3];
ll n,num,siz[N<<2];
vector<point> v[N<<2][2],tmp;
void Make(ll x){
ll ls=x*2,rs=x*2+1;
for(ll k=0;k<2;k++){
ll i=0,j=0,l1=v[ls][k].size()-1,l2=v[rs][k].size()-1;
tmp.clear();
while(i<=l1||j<=l2){
if(i>l1||(j<=l2&&v[rs][k][j]<v[ls][k][i]))
tmp.push_back(v[rs][k][j]),j++;
else tmp.push_back(v[ls][k][i]),i++;
}
ll cnt=0;
for(ll i=0;i<tmp.size();i++){
while(cnt>1&&((v[x][k][cnt-1]-v[x][k][cnt-2])^(tmp[i]-v[x][k][cnt-1]))>=0)
v[x][k].pop_back(),cnt--;
v[x][k].push_back(tmp[i]);cnt++;
}
}
return;
}
ll Calc(ll x,point p){
ll f=0;
if(p.y<0)p=z-p,f^=1;
ll l=0,r=v[x][f].size()-2;
while(l<=r){
ll mid=(l+r)>>1;
point tmp=v[x][f][mid+1]-v[x][f][mid];tmp.x*=-1;
if(p.x*tmp.x>=p.y*tmp.y)r=mid-1;
else l=mid+1;
}
return p*v[x][f][l];
}
void Change(ll x,ll L,ll R,ll pos,point p){
if(L==R){
v[x][0].push_back(p);
v[x][1].push_back(z-p);
return;
}
ll mid=(L+R)>>1;siz[x]++;
if(pos<=mid)Change(x*2,L,mid,pos,p);
else Change(x*2+1,mid+1,R,pos,p);
if(siz[x]==R-L+1)Make(x);
}
ll Ask(ll x,ll L,ll R,ll l,ll r,point p){
if(L==l&&R==r)return Calc(x,p);
ll mid=(L+R)>>1;
if(r<=mid)return Ask(x*2,L,mid,l,r,p);
if(l>mid)return Ask(x*2+1,mid+1,R,l,r,p);
return max(Ask(x*2,L,mid,l,mid,p),Ask(x*2+1,mid+1,R,mid+1,r,p));
}
void dc(ll &x,ll lastans) {
if(pe[0]=='E')return;
x=x^(lastans&0x7fffffff);
return;
}
signed main()
{
scanf("%lld%s",&n,pe);
ll last=0;
for(ll i=1;i<=n;i++){
char op[3];ll x,y,l,r;
scanf("%s%lld%lld",op,&x,&y);
dc(x,last);dc(y,last);
if(op[0]=='A'){
++num;
Change(1,1,n,num,point(x,y));
}
else{
scanf("%lld%lld",&l,&r);dc(l,last);dc(r,last);
printf("%lld\n",last=Ask(1,1,n,l,r,point(x,y)));
}
}
return 0;
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构