• 越野赛车问题——线段树分治+并查集


    题目

    【题目描述】
    小 $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$ 次训练中计划使用的车速,请帮助她对于每次训练,找
    到一条合法的路径(车速在所有车道的速度承受区间的交集内),使得路径上经
    过的车道数最大。
    【输入格式】
    输入文件的第一行包含两个正整数 $n,m$ ,表示广场数和训练次数。
    接下来 $n-1$ 行,每行四个正整数 $u_i,v_i,l_i,r_i(leq n)$,描述所有车道。
    最后 $m$ 行,每行一个正整数 $v(leq n)$ ,表示小 $H$ 每次训练时使用的车速。
    【输出格式】
    输出 $m$ 行,将每次训练时的行驶路径经过的最大车道数输出到文件中。
    【样例输入】
    5 3
    3 2 2 4
    1 5 2 5
    4 5 2 2
    1 2 3 5
    1
    2
    3
    【样例输出】
    0
    2
    3
    【数据范围与提示】
    保证 $n,m leq 7 imes 10^4 $

    题解

    考虑分治

    以赛道的限制为下标建线段树,将每一条边按 $ [l_i,r_i] $ 存入线段树

    查询的时候按线段树分治,构建出 $ [l,r] $ 的联通块,然后求联通块内的最长路径

    对于每一个联通块,记录下最长路的起点和终点 $ u,v $,合并两个联通块时,新的联通块的最长路的 $ u,v $ 一定是两个联通块的 $ u,v $,然后分讨一下即可

    求 $ u,v $ 的路径长,可以树上倍增lca(不反对树剖),因为保证联通块在树上

    但是由于联通块要支持撤回,并查集不能压缩路径,并且要记录下每一次的修改,然后在退出时撤回(不会写可持久化并查集)

    代码

     1 #include<bits/stdc++.h>
     2 #define LL long long
     3 #define pb push_back
     4 #define _(d) while(d(isdigit(ch=getchar())))
     5 using namespace std;
     6 int R(){
     7     int x;bool f=1;char ch;_(!)if(ch=='-')f=0;x=ch^48;
     8     _()x=(x<<3)+(x<<1)+(ch^48);return f?x:-x;}
     9 const int N=1e5+5;
    10 int n,m,head[N],cnt,f[N][22],lg,dep[N],fa[N],sz[N],ans[N],h[5];
    11 vector<int>tr[N<<2];
    12 struct edge{int to,nex;}e[N<<1];
    13 struct load{int u,v;}s[N],p[N];
    14 struct node{int v,id;}q[N];
    15 bool cmp(node a,node b){return a.v<b.v;}
    16 struct pig{int u,v,s;load x;};
    17 vector<pig>b[N<<2];
    18 void add(int s,int t){e[++cnt]=(edge){t,head[s]},head[s]=cnt;}
    19 #define Ls rt<<1
    20 #define Rs rt<<1|1
    21 void update(int rt,int l,int r,int ql,int qr,int x){
    22     if(ql<=l&&qr>=r){tr[rt].pb(x);return;}
    23     int mid=(l+r)>>1;
    24     if(ql<=mid)update(Ls,l,mid,ql,qr,x);
    25     if(qr>mid)update(Rs,mid+1,r,ql,qr,x);
    26     return;
    27 }
    28 void dfs(int u,int far){
    29     f[u][0]=far,dep[u]=dep[far]+1;
    30     for(int i=1;i<=lg;i++)f[u][i]=f[f[u][i-1]][i-1];
    31     for(int v,k=head[u];k;k=e[k].nex)
    32         if((v=e[k].to)!=far)
    33             dfs(v,u);
    34     return;
    35 }
    36 int lca(int x,int y){
    37     if(dep[x]>dep[y])swap(x,y);
    38     int i=lg;
    39     while(dep[x]<dep[y]){
    40         while(i>0&&dep[x]>dep[f[y][i]])i--;
    41         y=f[y][i];}
    42     i=lg;
    43     while(x!=y){
    44         while(i>0&&f[x][i]==f[y][i])i--;
    45         x=f[x][i],y=f[y][i];}
    46     return x;
    47 }
    48 int find(int x){return fa[x]==x?x:find(fa[x]);}
    49 void slove(int rt,int l,int r,int ql,int qr,int len){
    50     for(int j=tr[rt].size()-1;~j;j--){
    51         int k=tr[rt][j],u=s[k].u,v=s[k].v,fx=find(u),fy=find(v),w=0;
    52         h[1]=p[fx].u,h[2]=p[fx].v,h[3]=p[fy].u,h[4]=p[fy].v;
    53         if(sz[fx]>sz[fy])swap(fx,fy);
    54         b[rt].pb((pig){fx,fy,sz[fy],p[fy]});
    55         fa[fx]=fy,sz[fy]+=sz[fx];
    56         for(int x=1;x<4;x++)
    57             for(int y=x+1;y<=4;y++){
    58                 int u=h[x],v=h[y],far=lca(u,v),dis=dep[u]+dep[v]-dep[far]*2;
    59                 if(dis>w)w=dis,p[fy]=(load){u,v};
    60             }
    61         len=max(len,w);
    62     }
    63     if(l^r){
    64         int k=ql,mid=(l+r)>>1;
    65         while(q[k].v<=mid&&k<=qr)k++;
    66         if(k>ql)slove(Ls,l,mid,ql,k-1,len);
    67         if(k<=qr)slove(Rs,mid+1,r,k,qr,len);
    68     }
    69     else for(int i=ql;i<=qr;i++)ans[q[i].id]=len;
    70     
    71     for(int j=b[rt].size()-1;~j;j--)
    72         sz[b[rt][j].v]=b[rt][j].s,fa[b[rt][j].u]=b[rt][j].u,p[b[rt][j].v]=b[rt][j].x;
    73     return;
    74 }
    75         
    76 int main(){
    77     n=R(),m=R(),lg=log2(n)+1;
    78     for(int i=1;i<n;i++){
    79         int u=R(),v=R(),li=R(),ri=R();
    80         add(u,v),add(v,u),update(1,1,n,li,ri,i);
    81         s[i]=(load){u,v};
    82     }
    83     for(int i=1;i<=m;i++)q[i]=(node){R(),i};
    84     sort(q+1,q+1+m,cmp);
    85     for(int i=1;i<=n;i++)fa[i]=i,sz[i]=1,p[i]=(load){i,i};
    86     dfs(1,0);slove(1,1,n,1,m,0);
    87     for(int i=1;i<=m;i++)printf("%d
    ",ans[i]);
    88     return 0;
    89 }
    View Code
  • 相关阅读:
    缺陷与出路——一个游戏开发者的反思(转自《大众软件》)
    Arcengine 根据坐标串生成几何图形
    C#Arcengine通过坐标点生成面(环形)
    解析XML文件
    arcgis下载地址
    C#读写txt文件的两种方法介绍
    可伸缩性最佳实践:来自eBay的经验[精华强贴, 转之]
    请问怎样才能监视数据库表的变化?[转]
    VS2010中,在新建项目的时候,删除默认新建路径或曾经使用过的路径
    VS2010注册表垃圾清理
  • 原文地址:https://www.cnblogs.com/chmwt/p/10590489.html
Copyright © 2020-2023  润新知