【xsy1144】选物品 主席树
题目大意:N 件物品摆成一排,给每个物品定义两个属性 A 和B,两件物品的 差异度 定义为它们两种属性的差的绝对值中较大的一个。如果要求出一些物品的差异度,我们先定义一个 理想物品,使它与这些物品中每个物品的差异度的和最小,这些物品的差异度就是这个最小的和。给定N 个物品和Q组询问,询问从 L到 R 的物品差异度为多少。
我们设物品i和物品j之间的差异度为D,则
D=max{|Ai−Aj|,|Bi−Bj|}
=max{Ai−Aj,Aj−Ai,Bi−Bj,Bj−Bi}
我们令Xi=Ai+Bi,Xj=Aj+Bj,Yi=Ai−Bi,Yj=Aj−Bj。
则有D=max{(Xi−Xj)+(Yi−Yj),(Xi−Xj)−(Yi−Yj),−(Xi−Xj)+(Yi−Yj),−(Xi−Xj)−(Yi−Yj)}
简单化简后,D=|Xi−Xj|+|Yi−Yj|。
对于每一件物品,我们求出其对应的X值和Y值。
我们建两棵主席树,分别维护X值和Y值。
查询一个区间时,我们在两棵主席树上分别查询区间中位数,然后随便维护一下就行了。
时间复杂度:O(nlog n)。
1 #include<bits/stdc++.h> 2 #define M 100005 3 #define L long long 4 #define INF (2e9) 5 using namespace std; 6 7 L n,q,A[M]={0},B[M]={0}; 8 9 L lc[M*70]={0},rc[M*70]={0},siz[M*70]={0},cnt=0; L sum[M*70]={0}; 10 L root1[M]={0},root2[M]={0}; 11 void add(L &x,L l,L r,L now){ 12 cnt++; lc[cnt]=lc[x]; rc[cnt]=rc[x]; 13 siz[cnt]=siz[x]+1; sum[cnt]=sum[x]+now; x=cnt; 14 if(l==r) return; L mid=(l+r)>>1; 15 if(now<=mid) add(lc[x],l,mid,now); 16 else add(rc[x],mid+1,r,now); 17 } 18 L getkth(L x,L y,L l,L r,L k){ 19 if(l==r) return l; 20 L mid=(l+r)>>1; 21 if(siz[lc[y]]-siz[lc[x]]<k) return getkth(rc[x],rc[y],mid+1,r,k-(siz[lc[y]]-siz[lc[x]])); 22 return getkth(lc[x],lc[y],l,mid,k); 23 } 24 L getsum(L x,L l,L r,L ll,L rr){ 25 if(ll<=l&&r<=rr) return sum[x]; 26 L mid=(l+r)>>1,res=0; 27 if(ll<=mid) res+=getsum(lc[x],l,mid,ll,rr); 28 if(mid<rr) res+=getsum(rc[x],mid+1,r,ll,rr); 29 return res; 30 } 31 32 main(){ 33 scanf("%lld%lld",&n,&q); 34 for(L i=1;i<=n;i++) scanf("%lld",A+i); 35 for(L i=1;i<=n;i++) scanf("%lld",B+i); 36 for(L i=1;i<=n;i++){ 37 L upd1=A[i]+B[i],upd2=A[i]-B[i]; 38 root1[i]=root1[i-1]; root2[i]=root2[i-1]; 39 add(root1[i],-INF,INF,upd1); 40 add(root2[i],-INF,INF,upd2); 41 } 42 while(q--){ 43 L l,r,k,h;L res=0,mid; scanf("%lld%lld",&l,&r); 44 h=(r-l)/2+1; mid=(l+r)>>1; 45 k=getkth(root1[l-1],root1[r],-INF,INF,h); 46 res+=getsum(root1[r],-INF,INF,k,INF)-getsum(root1[l-1],-INF,INF,k,INF); 47 res-=k*(r-mid+1); 48 res+=(mid-l)*k; 49 res-=getsum(root1[r],-INF,INF,-INF,k-1)-getsum(root1[l-1],-INF,INF,-INF,k-1); 50 51 k=getkth(root2[l-1],root2[r],-INF,INF,h); 52 res+=getsum(root2[r],-INF,INF,k,INF)-getsum(root2[l-1],-INF,INF,k,INF); 53 res-=k*(r-mid+1); 54 res+=(mid-l)*k; 55 res-=getsum(root2[r],-INF,INF,-INF,k-1)-getsum(root2[l-1],-INF,INF,-INF,k-1); 56 57 printf("%.2lf\n",0.5*res); 58 } 59 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!