P6010 题解
honglan0301 · · 题解
题目分析
首先能想到一个正确但暴力的贪心,即如果
下面考虑如何快速维护这个过程,因为两种情况是对称的,故只考虑前者。
容易发现从世界
再考虑询问,不是很懂题解里怎么都要根据凸包建树倍增,既然你都维护出凸包了为什么不直接在上面二分呢?于是只需使用二分,时间复杂度
代码
#include <iostream>
#include <algorithm>
using namespace std;
#define int long long
int n,a[100005],q[100005],bh[100005],stk[100005],top,ansz[100005],ansm[100005];
bool cmp(int x,int y) {return a[x]>a[y];}
bool check(int x,int y,int k) {return (a[x]-a[k])*(y-k)<(a[y]-a[k])*(x-k);}
void ins(int x,bool zt)
{
while(top&&(zt^(x>stk[top]))||top>1&&check(stk[top-1],stk[top],x)) top--; stk[++top]=x;
if(zt^(a[q[x]]<a[x]))
{
if(zt^(q[x]>stk[1])) return; int l=2,r=top;
while(l<=r)
{
int mid=(l+r)>>1;
if((zt^(q[x]<stk[mid]))&&check(stk[mid],stk[mid-1],q[x])) l=mid+1;
else r=mid-1;
}
ansz[x]=a[stk[r]]-a[q[x]]; ansm[x]=stk[r]-q[x]; int gcdd=__gcd(ansz[x],ansm[x]);
ansz[x]/=gcdd; ansm[x]/=gcdd;
}
}
signed main()
{
cin.tie(0); cout.tie(0); ios::sync_with_stdio(0);
cin>>n; for(int i=1;i<=n;i++) cin>>a[i],bh[i]=i;
for(int i=1;i<=n;i++) cin>>q[i]; sort(bh+1,bh+n+1,cmp);
for(int i=1;i<=n;i++) ins(bh[i],0); top=0; //a[q[i]]<a[i]
for(int i=n;i>=1;i--) ins(bh[i],1);//a[q[i]]>a[i]
for(int i=1;i<=n;i++) if(!ansz[i]) cout<<"-1\n"; else cout<<ansz[i]<<"/"<<ansm[i]<<"\n";
}