ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

#4259. 越野赛车问题

2019-03-21 12:52:34  阅读:213  来源: 互联网

标签:4259 车道 越野赛 路径 问题 int far ql hd


题意
内存限制:256 MiB
时间限制:1000 ms
小 $H$ 是一位优秀的越野赛车女选手。现在她准备在 $A$ 山上进行赛车训练。
$A$ 山上一共有 $n$ 个广场,编号依次为 $1$ 到 $n$ ,这些广场之间通过 $n-1$条双向车道直接或间接地连接在一起。对于每条车道$i$ ,可以用四个正整数 $u_i,v_i,l_i,r_i$描述,表示车道连接广场 $u_i$ 和 $v_i$ ,其速度承受区间为$[l_i,r_i]$,即汽车必须以不小于$l_i$ 且不大于 $r_i$ 的速度经过车道$i$ 。
小 $H$ 计划进行 $m$ 次训练,每次她需要选择 $A$ 山上的一条简单路径,然后在这条路径上行驶。但小 $H$ 不喜欢改变速度,所以每次训练时的车速都是固定的。
现在小 $H$ 告诉你她在$m$ 次训练中计划使用的车速,请帮助她对于每次训练,找到一条合法的路径(车速在所有车道的速度承受区间的交集内),使得路径上经过的车道数最大。

$1 \leq n,m,l_i,r_i,v_i \leq 70000$

题解
建一棵以速度为下标的线段树,把树上的每条边放到线段树中,然后对于询问进行线段树分治,每次走到一个区间就将里面的每条边的两个端点连成一个并查集,这个并查集要维护的信息是里面的点中的最长链,由于之后要撤销,所以不能路径压缩,改用启发式合并
对于维护最长链,只需要将原来两个并查集的四个点拿出来,分别跑出路径大小,判断即可,这里需要用 $rmq$ 维护两点间的 $lca$

代码

#include <bits/stdc++.h>
#define I inline
using namespace std;const int N=70005;
int n,m,t,f[N*2][18],c,d[N],fa[N],X[N],Y[N],L[N];
int R[N],ans[N],sz[N],e[N],hd[N],V[N*2],nx[N*2];
vector<int>g[N*4];struct O{int v,id;}p[N];struct far{int x,y;}h[N];
struct E{int x,f,s;far k;};vector<E>a[N*4];
I void add(int u,int v){V[++t]=v;nx[t]=hd[u];hd[u]=t;}
I void dfs(int x,int F){
    f[++c][0]=x;d[x]=d[F]+1;e[x]=c;
    for (int i=hd[x];i;i=nx[i])
        if (V[i]!=F) dfs(V[i],x),f[++c][0]=x;
}
I int lca(int l,int r){
    if (l>r) swap(l,r);int i=log2(r-l+1);
    if (d[f[l][i]]<d[f[r-(1<<i)+1][i]])
        return f[l][i];return f[r-(1<<i)+1][i];
}
I bool cmp(O A,O B){return A.v<B.v;}
I int get(int x){return x==fa[x]?x:get(fa[x]);}
I int dis(int x,int y){return d[x]+d[y]-2*d[lca(e[x],e[y])];}
#define Ls k<<1
#define Rs k<<1|1
#define mid ((l+r)>>1)
I void update(int k,int l,int r,int ql,int qr,int v){
    if (ql<=l && r<=qr){g[k].push_back(v);return;}
    if (mid>=ql) update(Ls,l,mid,ql,qr,v);
    if (mid<qr) update(Rs,mid+1,r,ql,qr,v);
}
I void query(int k,int l,int r,int ql,int qr,int ax){
    for (int v,i=g[k].size()-1;~i;i--){
        v=g[k][i];int k1=get(X[v]),k2=get(Y[v]);
        if (sz[k1]<sz[k2]) swap(k1,k2);
        a[k].push_back((E){k2,k1,sz[k1],h[k1]});
        int T[2][2],now=0;
        T[0][0]=h[k1].x;T[0][1]=h[k1].y;
        T[1][0]=h[k2].x;T[1][1]=h[k2].y;
        for (int X1=0;X1<2;X1++) for (int Y1=0;Y1<2;Y1++)
        for (int X2=0;X2<2;X2++) for (int Y2=0;Y2<2;Y2++)
        if ((X1^X2) || (Y1^Y2)){
            int nw=dis(T[X1][Y1],T[X2][Y2]);
            if (nw>now) now=nw,h[k1]=(far){T[X1][Y1],T[X2][Y2]};
        }
        fa[k2]=k1;sz[k1]+=sz[k2];ax=max(ax,now);
    }
    if (l^r){
        int T=ql;for (;T<=qr;T++) if (p[T].v>mid) break;
        if (T>ql) query(Ls,l,mid,ql,T-1,ax);
        if (T<=qr) query(Rs,mid+1,r,T,qr,ax);
    }
    else for (int i=ql;i<=qr;i++) ans[p[i].id]=ax;
    for (int i=a[k].size()-1;~i;i--)
        sz[a[k][i].f]=a[k][i].s,h[a[k][i].f]=a[k][i].k,
        fa[a[k][i].x]=a[k][i].x;
}
int main(){
    scanf("%d%d",&n,&m);
    for (int i=1;i<n;i++)
        scanf("%d%d%d%d",&X[i],&Y[i],&L[i],&R[i]),
        add(X[i],Y[i]),add(Y[i],X[i]),
        update(1,1,n,L[i],R[i],i);
    dfs(1,0);for (int i=c;i;i--)
        for (int j=1;i+(1<<j)<=c+1;j++){
            if (d[f[i][j-1]]<d[f[i+(1<<(j-1))][j-1]])
                f[i][j]=f[i][j-1];
            else f[i][j]=f[i+(1<<(j-1))][j-1];
        }
    for (int i=1;i<=m;i++) scanf("%d",&p[i].v),p[i].id=i;
    for (int i=1;i<=n;i++) fa[i]=i,sz[i]=1,h[i]=(far){i,i};
    sort(p+1,p+m+1,cmp);query(1,1,n,1,m,0);
    for (int i=1;i<=m;i++) printf("%d\n",ans[i]);
    return 0;
}

 

标签:4259,车道,越野赛,路径,问题,int,far,ql,hd
来源: https://www.cnblogs.com/xjqxjq/p/10570902.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有