#单调栈,树状数组#CF1635F Closest Pair
题目
设 \(f(x,y)=|a_x-a_y|*(w_x+w_y)\),其中 \(a\) 单调递增
多组询问求 \(\min_{l\leq l'<r'\leq r}\{f(l',r')\}\)
\(n,Q\leq 3*10^5,|a|,w\leq 10^9\)
分析
可以发现尽量让 \(l',r'\) 靠近最优,处理出每个数的不超过这个数的前驱和后继,
答案一定只能在这最多 \(2n\) 个点对中产生,所以直接离线按右端点排序用树状数组维护即可
代码
#include <cstdio>
#include <cctype>
#include <vector>
using namespace std;
const int N=300011; struct node{int y,next;}e[N];
int x[N],a[N],n,Q,st[N],Top,as[N]; vector<int>K[N];
typedef long long lll; lll ans[N],c[N];
int iut(){
int ans=0,f=1; char c=getchar();
while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans*f;
}
void print(lll ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
lll min(lll a,lll b){return a<b?a:b;}
void update(int x,lll y){for (;x<=n;x+=-x&x) c[x]=min(c[x],y);}
lll query(int x){lll ans=4e18; for (;x;x-=-x&x) ans=min(ans,c[x]); return ans;}
int main(){
n=iut(),Q=iut();
for (int i=1;i<=n;++i){
x[i]=iut(),a[i]=iut(),c[i]=4e18;
while (Top&&a[st[Top]]>a[i]) --Top;
K[i].push_back(st[Top]),st[++Top]=i;
}
Top=0;
for (int i=n;i;--i){
while (Top&&a[st[Top]]>a[i]) --Top;
K[st[Top]].push_back(i),st[++Top]=i;
}
for (int i=1;i<=Q;++i){
int l=iut(),r=iut();
e[i]=(node){l,as[r]},as[r]=i;
}
for (int i=1;i<=n;++i){
int len=K[i].size();
for (int j=0;j<len;++j){
int t=K[i][j];
update(n-t+1,1ll*(x[i]-x[t])*(a[i]+a[t]));
}
for (int j=as[i];j;j=e[j].next) ans[j]=query(n-e[j].y+1);
}
for (int i=1;i<=Q;++i) print(ans[i]),putchar(10);
return 0;
}

浙公网安备 33010602011771号