码迷,mamicode.com
首页 > 其他好文 > 详细

CF704E Iron Man

时间:2020-02-23 19:50:30      阅读:60      评论:0      收藏:0      [点我收藏+]

标签:clear   char   最小   abs   get   break   while   puts   oid   

Link
先树剖,把一条路径拆成若干个重链上的区间。
那么对于每一条重链,我们把问题转化为了:给定一些线段,求线段之间的\(x\)坐标最小的交点。
那么我们按横坐标扫描线,用multiset维护线段。
加入一条线段时,利用这条线段与和它纵坐标相邻的两条线段更新答案。
删除一条线段时,利用和它纵坐标相邻的两条线段更新答案。
如果横坐标大于目前已知的最小横坐标,那么直接退出。

#include<set>
#include<cmath>
#include<cstdio>
#include<cctype>
#include<vector>
#include<algorithm>
using db=double;
const int N=100007;const db eps=1e-10,inf=1e10;
int n,m,fa[N],dep[N],size[N],son[N],top[N],vis[N];db ans=inf,t,c[N],ed[N];
struct line{int x,id,o;db t,c;}b[N];
db cal(const line&x){return dep[x.x]+(t-x.t)*c[x.id];}
int operator<(const line&a,const line&b){return cal(a)<cal(b);}
std::vector<int>e[N];std::vector<line>f[N];std::multiset<line>s;
int read(){int x=0,c=getchar();while(!isdigit(c))c=getchar();while(isdigit(c))(x*=10)+=c&15,c=getchar();return x;}
void dfs(int u){size[u]=1;for(int v:e[u])if(v^fa[u])fa[v]=u,dep[v]=dep[u]+1,dfs(v),size[u]+=size[v],son[u]=size[v]>size[son[u]]? v:son[u];}
void dfs(int u,int tp){top[u]=tp;if(son[u])dfs(son[u],tp);for(int v:e[u])if(v^fa[u]&&v^son[u])dfs(v,v);}
int lca(int u,int v){for(;top[u]^top[v];u=fa[top[u]])if(dep[top[v]]>dep[top[u]])std::swap(u,v);return dep[u]>dep[v]? v:u;}
db cal(int u,int v,db c){return (dep[u]-dep[v])/c;}
void update(const line&x,const line&y)
{
    db v=cal(y)-cal(x),p=fabs(v)<eps? 0:(cal(y)-cal(x))/(c[x.id]-c[y.id]);
    if(p>-eps&&p+t<std::min(ed[x.id],ed[y.id])+eps) ans=std::min(ans,p+t);
}
void work(int u)
{
    s.clear(),std::sort(f[u].begin(),f[u].end(),[](const line&a,const line&b){return fabs(a.t-b.t)<eps? a.o>b.o:a.t<b.t;});
    for(line x:f[u]) if(x.o) b[x.id]=x; else ed[x.id]=x.t;
    for(line x:f[u])
    {
    if((t=x.t)>ans+eps) break;
    if(x.o)
    {
        auto it=s.insert(x);c[x.id]=x.c;
        if(it!=s.begin()) update(x,*prev(it));
        if(++it!=s.end()) update(x,*it);
    }
    else
    {
        auto it=s.find(b[x.id]);
        if(it!=s.begin()&&next(it)!=s.end()) update(*prev(it),*next(it));
        if(it!=s.end()) s.erase(it);
    }
    }
}
int main()
{
    n=read(),m=read();
    for(int i=1,u,v;i<n;++i) u=read(),v=read(),e[u].push_back(v),e[v].push_back(u);
    dfs(1),dfs(1,1);
    for(int i=1;i<=m;++i)
    {
    db t=read(),T;c[i]=read();int x=read(),y=read(),u=x,v=y,p=lca(u,v),flg=1;T=t+cal(u,p,c[i]);
    for(;top[u]^top[v];u=fa[top[u]])
    {
        if(dep[top[u]]<dep[top[v]]) std::swap(u,v),flg^=1;
        if(flg) f[top[u]].push_back({u,i,1,t+cal(x,u,c[i]),-c[i]}),f[top[u]].push_back({fa[top[u]],i,0,t+cal(x,fa[top[u]],c[i]),-c[i]});
        else f[top[u]].push_back({u,i,0,T+cal(u,p,c[i]),c[i]}),f[top[u]].push_back({fa[top[u]],i,1,T+cal(fa[top[u]],p,c[i]),c[i]});
    }
    if(dep[u]<dep[v]) std::swap(u,v),flg^=1;
    if(flg) f[top[u]].push_back({u,i,1,t+cal(x,u,c[i]),-c[i]}),f[top[u]].push_back({v,i,0,T,-c[i]});
    else f[top[u]].push_back({v,i,1,T,c[i]}),f[top[u]].push_back({u,i,0,T+cal(u,v,c[i]),c[i]});
    }
    for(int i=1;i<=n;++i) if(!vis[top[i]]) vis[top[i]]=1,work(top[i]);
    fabs(ans-inf)<eps? puts("-1"):printf("%.10lf",ans);
}

CF704E Iron Man

标签:clear   char   最小   abs   get   break   while   puts   oid   

原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12353331.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!