QOJ.ac

QOJ

Type: Editorial

Status: Open

Posted by: liumonong

Posted at: 2026-01-07 16:05:36

Last updated: 2026-01-07 16:06:37

Back to Problem

分治做法题解

令左边速度为 $spd_l$,右边速度为 $spd_r$,则 $\frac{m-l}{spd_l}=\frac{r-m}{spd_r}$,即 $\frac{spd_l}{m-l}=\frac{spd_r}{r-m}$,得到 $spd_l : spd_r = m-l : r-m$,由于 $spd_l+spd_r=1$,故:

  • $spd_l = \frac{m-l}{r-l},spd_r=\frac{r-m}{r-l}$

令 $s = r-l$,则 $spd_l=\frac{m-l}{s},spd_r=\frac{r-m}{s}$

对于第 $i$ 个人:

  • 若 $x_i \le m$ $f_i(m) = y_i+\frac{x_i-l}{spd_l} = y_i+\frac{(x_i-l)s}{m-l}$

  • 若 $x_i \gt m$ $f_i(m)=y_i+\frac{(r-x_i)s}{r-m} $

考虑令 $u = \frac{m-l}{s} \in [0,1],p_i=x_i-l,q_i=s-p_i,u_i=\frac{x_i-l}{s}$

$$ f_i(u)=\begin{cases}y_i+\frac{p_i}{u}&u_i \le u \\y_i+\frac{q_i}{1-u} & u_i \gt u\\\end{cases} $$

考虑分治 f(l,r) 表示考虑 $[l,r]$ 区间所有玩家,其中每一段区间的胜利玩家。

  • $l=r$返回 $([0,1],x)$

  • $l \lt r$返回 $merge(f(l,mid),f(mid+1,r))$

对于 merge 过程。

双指针从前到后扫描。

开始位置必然都是 $0$,结束位置必然都是 $1$。

对于最前面的两个区间,必然是一段前缀重合,此时对前缀单独提取计算答案。

然后删除双方公共前缀,剩下一段继续匹配。

考虑前缀怎么处理。

相当于问一段连续区间 $[l,r]$,$a,b$ 两个人的获胜情况。

现在找出区间 $[l,r]$ 包含哪些 $a,b$ 两人的函数交点,另外 $a,b$ 的 $u$ 值也作为切点。

按照交点将区间 $[l,r]$ 拆分为若干个子区间分别处理。

子区间取中点比较大小即可确定 $a,b$ 谁赢得子区间。

vector<pair<double,double> > cut1(l,r,a,b) 返回 $[l,r]$ 区间被 $a,b$ 的 $u$ 值切开的结果。

vector<pair<double,double> > cut2(l,r,a,b) 接受双方函数一致的区间,返回按照双方交点切开的结果。

void smalldetect(vector<SEQ>& ans,double l,double r,int a,int b) 接受双方函数一致且不存在交点的区间,将答案加入 ans。

void detectwinner(vector<SEQ>& ans,double l,double r,int a,int b) 拆分 $[l,r]$ 区间的 $a,b$ 两人胜利区间,并将区间答案加入 ans

  • 对于 $y_a + \frac{p_a}{x} = y_b+\frac{p_b}{x}$,可以解出 $x = \frac{p_a-p_b}{y_b-y_a}$

  • 对于 $y_a + \frac{q_a}{1-x} = y_b+\frac{q_b}{1-x}$,可以解出 $x=1-\frac{q_a-q_b}{y_b-y_a}$

  • 对于 $y_a + \frac{p_a}{x} = y_b+\frac{q_b}{1-x}$,令 $t=y_a-y_b$,则可以解出 $x=\frac{-t+p_a+q_b\pm\sqrt{(t-p_a-q_b)^2-4(-t)(p_a)}}{-2t}$

  • 对于 $y_a+\frac{q_a}{1-x} = y_b+\frac{p_b}{x}$,令 $t=y_b-y_a$,则可以解出 $x = \frac{-t+p_b+q_a\pm\sqrt{(t-p_b-q_a)^2-4(-t)(p_b)}}{-2t}$

#include <bits/stdc++.h>
using namespace std;
#define FOR(i,a,b) for(auto i=(a);i<=(b);i++)
#define REP(i,a,b) for(auto i=(a);i>=(b);i--)
#define FORK(i,a,b,k) for(auto i=(a);i<=(b);i+=(k))
#define REPK(i,a,b,k) for(auto i=(a);i>=(b);i-=(k))
#define pb push_back
#define mkpr make_pair
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef vector<int> vi;
template<class T>
void ckmx(T& a,T b){
    a=max(a,b);
}
template<class T>
void ckmn(T& a,T b){
    a=min(a,b);
}
template<class T>
T gcd(T a,T b){
    return !b?a:gcd(b,a%b);
}
template<class T>
T lcm(T a,T b){
    return a/gcd(a,b)*b;
}
#define gc getchar()
#define eb emplace_back
#define pc putchar
#define ep empty()
#define fi first
#define se second
#define pln pc('\n');
#define islower(ch) (ch>='a'&&ch<='z')
#define isupper(ch) (ch>='A'&&ch<='Z')
#define isalpha(ch) (islower(ch)||isupper(ch))
template<class T>
void wrint(T x){
    if(x<0){
        x=-x;
        pc('-');
    }
    if(x>=10){
        wrint(x/10);
    }
    pc(x%10^48);
}
template<class T>
void wrintln(T x){
    wrint(x);
    pln
}
template<class T>
void read(T& x){
    x=0;
    int f=1;
    char ch=gc;
    while(!isdigit(ch)){
        if(ch=='-')f=-1;
        ch=gc;
    }
    while(isdigit(ch)){
        x=(x<<1)+(x<<3)+(ch^48);
        ch=gc;
    }
    x*=f;
}
void ioopti(){
    ios::sync_with_stdio(0);
    cin.tie(0);
}
void io(){
    freopen("anticipate.in","r",stdin);
    freopen("anticipate.out","w",stdout);
}
const double eps=1e-12;
bool chkeq(double& a,double& b){
    return abs(a-b)<=eps;
}
const int maxn=2e5+5;
int n;
double l,r,x[maxn],y[maxn];
double p[maxn],q[maxn],u[maxn],s;
struct SEQ{
    double l,r;
    int winid;
    SEQ(double l,double r,int winid):l(l),r(r),winid(winid){}
};
vector<pair<double,double> > cut1(double l,double r,int a,int b){
    vector<double> cuts;
    if(u[a]>=l&&u[a]<=r)cuts.eb(u[a]);
    if(u[b]>=l&&u[b]<=r)cuts.eb(u[b]);
    if(cuts.empty())return {mkpr(l,r)};
    sort(cuts.begin(),cuts.end());
    cuts.erase(unique(cuts.begin(),cuts.end()),cuts.end());
    vector<pair<double,double> > res;
    res.eb(mkpr(l,cuts[0]));
    FOR(i,1,cuts.size()-1)res.eb(mkpr(cuts[i-1],cuts[i]));
    res.eb(mkpr(cuts.back(),r));
    return res;
}
double sqr(double x){
    return x*x;
}
vector<pair<double,double> > cut2(double l,double r,int a,int b){
    double mid=(l+r)/2;
    bool a_lef=(mid>=u[a]);
    bool b_lef=(mid>=u[b]);
    vector<double> cuts;
    if(a_lef&&b_lef){
        if(!chkeq(y[a],y[b])){
            double x=(p[a]-p[b])/(y[b]-y[a]);
            if(x>=l&&x<=r){
                cuts.eb(x);
            }
        }
    }else if(a_lef&&!b_lef){
        // a 左边,但是 b 右边
        if(chkeq(y[a],y[b])){
            double x=p[a]/(p[a]+q[b]);
            if(x>=l&&x<=r)cuts.eb(x);    
        }else{
            double t=y[a]-y[b];
            if(sqr(t-p[a]-q[b])-4*(-t)*p[a]>=0){
                double x1=(-t+p[a]+q[b]+sqrt(sqr(t-p[a]-q[b])-4*(-t)*p[a]))/(-2*t);
                double x2=(-t+p[a]+q[b]-sqrt(sqr(t-p[a]-q[b])-4*(-t)*p[a]))/(-2*t);
                if(x1>=l&&x1<=r)cuts.eb(x1);
                if(x2>=l&&x2<=r)cuts.eb(x2);
            }
        }
    }else if(!a_lef&&b_lef){
        if(chkeq(y[a],y[b])){
            double x=p[b]/(p[b]+q[a]);
            if(x>=l&&x<=r)cuts.eb(x);
        }else{
            double t=y[b]-y[a];
            if(sqr(t-p[b]-q[a])-4*(-t)*p[b]>=0){
                double x1=(-t+p[b]+q[a]+sqrt(sqr(t-p[b]-q[a])-4*(-t)*p[b]))/(-2*t);
                double x2=(-t+p[b]+q[a]-sqrt(sqr(t-p[b]-q[a])-4*(-t)*p[b]))/(-2*t);
                if(x1>=l&&x1<=r)cuts.eb(x1);
                if(x2>=l&&x2<=r)cuts.eb(x2);
            }
        }
    }else{
        if(!chkeq(y[a],y[b])){
            double x=1-(q[a]-q[b])/(y[b]-y[a]);
            if(x>=l&&x<=r){
                cuts.eb(x);
            }
        }
    }
    sort(cuts.begin(),cuts.end());
    cuts.erase(unique(cuts.begin(),cuts.end()),cuts.end());
    vector<pair<double,double> > res;
    if(cuts.empty()){
        res.eb(l,r);
    }else{
        res.eb(mkpr(l,cuts[0]));
        FOR(i,1,cuts.size()-1)res.eb(mkpr(cuts[i-1],cuts[i]));
        res.eb(mkpr(cuts.back(),r));
    }
    return res;
}
double getval(int id,double m){
    if(m>=u[id]){
        return y[id]+p[id]/m;
    }else{
        return y[id]+q[id]/(1-m);
    }
}
void smalldetect(vector<SEQ>& ans,double l,double r,int a,int b){
    double mid=(l+r)/2;
    if(getval(a,mid)>getval(b,mid))ans.eb(SEQ{l,r,a});
    else ans.eb(SEQ{l,r,b});
}
void detectwinner(vector<SEQ>& ans,double l,double r,int a,int b){
    auto fircuts=cut1(l,r,a,b);
    for(auto [l1,r1]:fircuts){
        auto seccuts=cut2(l1,r1,a,b);
        for(auto [l2,r2]:seccuts){
            smalldetect(ans,l2,r2,a,b);
        }
    }
}
vector<SEQ> merge(vector<SEQ> a,vector<SEQ> b){
    vector<SEQ> res;
    int i=0,j=0;
    while(i<a.size()&&j<b.size()){
        double mn=min(a[i].r,b[j].r);
        detectwinner(res,a[i].l,mn,a[i].winid,b[j].winid);
        a[i].l=mn,b[j].l=mn;
        if(chkeq(a[i].l,a[i].r))i++;
        if(chkeq(b[j].l,b[j].r))j++;
    }
    vector<SEQ> tmp;
    for(auto [l,r,winid]:res){
        if(!tmp.empty()&&winid==tmp.back().winid){
            tmp.back().r=r;
        }else{
            tmp.eb(SEQ{l,r,winid});
        }
    }
    // assert(i==a.size()&&j==b.size())
    return tmp;
}
vector<SEQ> f(int l,int r){
    if(l==r){
        return {SEQ(0.0,1.0,l)};
    }
    int mid=(l+r>>1);
    return merge(f(l,mid),f(mid+1,r));
}
double ans[maxn];
void solve(int id_of_test){
    {
        scanf("%d%lf%lf",&n,&l,&r);
        FOR(i,1,n){
            scanf("%lf",&x[i]);
        }
        FOR(i,1,n){
            scanf("%lf",&y[i]);
        }
    }
    {
        s=r-l;
        FOR(i,1,n){
            p[i]=x[i]-l;
            q[i]=s-p[i];
            u[i]=(x[i]-l)/s;
        }
    }
    auto res=f(1,n);
    for(auto [l,r,winid]:res){
        ans[winid]+=r-l;
    }
    FOR(i,1,n){
        printf("%.12lf\n",ans[i]);
    }
}
int main()
{
   // io();
  //  int num;
  //  read(num);
    int T;
    T=1;
    FOR(_,1,T){
        solve(_);
    }
    return 0;
}
/*
1. 对题意的理解能否和样例对的上?  
2. 每一步操作,能否和自己的想法对应上?  
3. 每一步操作的正确性是否有保证?  
4. 是否考虑到了所有的 case?特别是极限数据。
5. 变量的数据类型是否与其值域匹配?
6. 时间复杂度有保证吗?
7. 空间多少 MB?  
*/

Comments

No comments yet.