Dash Speed

本文深入探讨了树上分治算法的应用,特别是在解决比特山飙车问题中的具体实现。通过对树状结构进行分治处理,算法能够有效地寻找路径上车道数量最多的合法道路。文章详细介绍了如何使用并查集更新树的直径,以及在合并树时进行的特判处理,提供了完整的代码实现。

题目大意:

比特山是比特镇的飙车圣地。在比特山上一共有n 个广场,编号依次为1 到n,这些广场之间通过n - 1 条双向车道直接或间接地连接在一起,形成了一棵树的结构。
因为每条车道的修建时间以及建筑材料都不尽相同,所以可以用两个数字li; ri 量化地表示一条车道的承受区间,只有当汽车以不小于li 且不大于ri 的速度经过这条车道时,才不会对路面造成伤害。
Byteasar 最近新买了一辆跑车,他想在比特山飙一次车。Byteasar 计划选择两个不同的点S; T,然后在它们树上的最短路径上行驶,且不对上面任意一条车道造成伤害。
Byteasar 不喜欢改变速度,所以他会告诉你他的车速。为了挑选出最合适的车速,Byteasar 一共会向你询问m 次。请帮助他找到一条合法的道路,使得路径上经过的车道数尽可能多。

数据范围n,m<=70000.

题解:

(蒟蒻眼中)比较神的树上分治。做法分治[ l , r ] :(丑图奉上)

其中每一个矩形代表分治区间,圆代表提取答案的地方。

每当访问到矩形/圆时,将对应区间加的边更新并查集,然后不断用新集的直径更新当前答案。

(ps.当两棵树合并时,新树的直径一定在旧树的端点中产生。这里需要6次特判。)

每当返回时,将原来的更新取消。可以先记录栈的tl,然后将栈还原。

细节比较多,详细见代码:


 

upd:由于之前代码太丑被和谐,附上新代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 70050;
template<typename T>
inline void read(T&x)
{
    T f = 1,c = 0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();}
    x = f*c;
}
int n,m,hed[N],cnt,dep[N],siz[N],fa[N],son[N],tp[N];
struct EG
{
    int to,nxt;
}e[N<<1];
void ae(int f,int t)
{
    e[++cnt].to = t;
    e[cnt].nxt = hed[f];
    hed[f] = cnt;
}
void dfs1(int u,int f)
{
    fa[u]=f,dep[u]=dep[f]+1,siz[u]=1;
    for(int j=hed[u],to;j;j=e[j].nxt)
        if((to=e[j].to)!=f)
        {
            dfs1(to,u),siz[u]+=siz[to];
            if(siz[son[u]]<siz[to])son[u]=to;
        }
}
void dfs2(int u,int Top)
{
    tp[u] = Top;
    if(!son[u])return ;
    dfs2(son[u],Top);
    for(int j=hed[u],to;j;j=e[j].nxt)if((to=e[j].to)!=fa[u]&&to!=son[u])
        dfs2(to,to);
}
int get_lca(int x,int y)
{
    while(tp[x]!=tp[y])
    {
        if(dep[tp[x]]<dep[tp[y]])swap(x,y);
        x = fa[tp[x]];
    }
    return dep[x]<dep[y]?x:y;
}
int get_dis(int x,int y){return dep[x]+dep[y]-2*dep[get_lca(x,y)];}
struct Tree
{
    int a,b,w;
    Tree(){}
    Tree(int a,int b,int w):a(a),b(b),w(w){}
    Tree operator + (const Tree&x)const
    {
        Tree ret = Tree(a,b,w);int tmp;
        if(ret.w<x.w)ret=x;
        tmp=get_dis(a,x.a);if(ret.w<tmp)ret=Tree(a,x.a,tmp);
        tmp=get_dis(a,x.b);if(ret.w<tmp)ret=Tree(a,x.b,tmp);
        tmp=get_dis(b,x.a);if(ret.w<tmp)ret=Tree(b,x.a,tmp);
        tmp=get_dis(b,x.b);if(ret.w<tmp)ret=Tree(b,x.b,tmp);
        return ret;
    }
};
int ans[N];
struct segtree
{
    struct point
    {
        Tree s;
        int ff,siz;
    }p[N];
    struct node
    {
        int u;point p0;
        node(){}
        node(int u,point p0):u(u),p0(p0){}
    }sta[N<<5];
    int hd[N<<2],ct,tl;
    struct edge
    {
        int u,v,nxt;
    }E[N<<5];
    void ae(int f,int u,int v)
    {
        E[++ct].u = u;
        E[ct].v = v;
        E[ct].nxt = hd[f];
        hd[f] = ct;
    }
    void insert(int l,int r,int u,int ql,int qr,int&lp,int&rp)
    {
        if(l==ql&&r==qr){ae(u,lp,rp);return ;}
        int mid = (l+r)>>1;
        if(qr<=mid)insert(l,mid,u<<1,ql,qr,lp,rp);
        else if(ql>mid)insert(mid+1,r,u<<1|1,ql,qr,lp,rp);
        else insert(l,mid,u<<1,ql,mid,lp,rp),insert(mid+1,r,u<<1|1,mid+1,qr,lp,rp);
    }
    int findff(int u){return u==p[u].ff?u:findff(p[u].ff);}
    void merge(int u,int v,int&now)
    {
        u = findff(u),v = findff(v);
        if(u==v)return ;
        if(p[u].siz>p[v].siz)swap(u,v);
        sta[++tl]=node(u,p[u]),sta[++tl]=node(v,p[v]);
        p[v].s=p[v].s+p[u].s,p[u].ff=v;
        if(p[u].siz==p[v].siz)p[v].siz++;
        now = max(now,p[v].s.w);
    }
    void rep(int las)
    {
        while(tl!=las)p[sta[tl].u]=sta[tl].p0,tl--;
    }
    void sol(int l,int r,int u,int now)
    {
        int tim = tl;
        for(int j=hd[u];j;j=E[j].nxt)
            merge(E[j].u,E[j].v,now);
        if(l==r){ans[l]=now;rep(tim);return ;}
        int mid = (l+r)>>1;
        sol(l,mid,u<<1,now);sol(mid+1,r,u<<1|1,now);
        rep(tim);
    }
}tr;
int main()
{
//    freopen("tt.in","r",stdin);
    read(n),read(m);
    for(int u,v,l,r,i=1;i<n;i++)
    {
        read(u),read(v),read(l),read(r);
        ae(u,v),ae(v,u);tr.insert(1,n,1,l,r,u,v);
    }
    dfs1(1,0),dfs2(1,1);
    for(int i=1;i<=n;i++)
        tr.p[i].ff=i,tr.p[i].siz=1,tr.p[i].s=Tree(i,i,0);
    tr.sol(1,n,1,0);
    for(int i=1,x;i<=m;i++)
        read(x),printf("%d\n",ans[x]);
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/LiGuanlin1124/p/9863159.html

// Assets/Scripts/Gameplay/CharacterSystem/Controllers/PlayerMovement.cs using UnityEngine; // Assets/Scripts/Gameplay/CharacterSystem/PlayerMovement.cs [RequireComponent(typeof(CharacterBase))] public class PlayerMovement : MonoBehaviour { // 自动获取的引用 private CharacterBase _character; private RunTimeData _runtimeData; private Rigidbody2D _rb; [Header("地面检测")] public Transform groundCheck; public float groundCheckRadius = 0.2f; public LayerMask groundLayer; private bool _isGrounded; private bool _isDashing; private float _dashTimer; void Start() { // 自动获取必要组件 _rb = GetComponent<Rigidbody2D>(); _character = GetComponent<CharacterBase>(); _runtimeData = _character.runtimeData; // 自动创建地面检测点(如果忘记设置) if (groundCheck == null) { groundCheck = new GameObject("GroundCheck").transform; groundCheck.SetParent(transform); groundCheck.localPosition = new Vector3(0, -0.5f, 0); } } void FixedUpdate() { // 地面检测 _isGrounded = Physics2D.OverlapCircle( groundCheck.position, groundCheckRadius, groundLayer ); // 绘制检测范围(场景视图可见) Debug.DrawRay(groundCheck.position, Vector2.down * groundCheckRadius, Color.green); } public void Move(float horizontalInput) { // 安全获取移动速度 float moveSpeed = _runtimeData.currentStats.moveSpeed; // 应用移动 _rb.velocity = new Vector2( horizontalInput * moveSpeed, _rb.velocity.y ); } public void Jump() { if (!_isGrounded) return; // 安全获取跳跃力 float jumpForce = _runtimeData.currentStats.jumpForce; // 应用跳跃 _rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse); } public void Dash() { // 修复条件:只能在地面冲刺 && 不在冲刺中 if (_isDashing || !_isGrounded) return; _isDashing = true; _dashTimer = 0.2f; // 冲刺持续时间 // 获取角色朝向 float dashDirection = transform.localScale.x > 0 ? 1 : -1; // 从运行时数据获取速度(修复访问方式) float baseSpeed = _runtimeData.currentStats.moveSpeed; float dashSpeed = baseSpeed * 3f; // 应用冲刺力 _rb.velocity = new Vector2(dashDirection * dashSpeed, 0); } // 结束冲刺方法(修复版) public void EndDash() { _isDashing = false; // 保留部分动量 _rb.velocity = new Vector2(_rb.velocity.x * 0.5f, _rb.velocity.y); } // 可视化地面检测范围 private void OnDrawGizmosSelected() { if (groundCheck == null) return; Gizmos.color = Color.green; Gizmos.DrawWireSphere(groundCheck.position, groundCheckRadius); } // 添加调试信息 void OnGUI() { GUILayout.Label($"冲刺状态: {_isDashing}"); GUILayout.Label($"着地状态: {_isGrounded}"); if (_runtimeData != null) { GUILayout.Label($"移动速度: {_runtimeData.currentStats.moveSpeed}"); } } } // Assets/Scripts/Gameplay/CharacterSystem/Controllers/PlayerMovement.cs using UnityEngine; // Assets/Scripts/Gameplay/CharacterSystem/PlayerMovement.cs [RequireComponent(typeof(CharacterBase))] public class PlayerMovement : MonoBehaviour { // 自动获取的引用 private CharacterBase _character; private RunTimeData _runtimeData; private Rigidbody2D _rb; [Header("地面检测")] public Transform groundCheck; public float groundCheckRadius = 0.2f; public LayerMask groundLayer; private bool _isGrounded; private bool _isDashing; private float _dashTimer; void Start() { // 自动获取必要组件 _rb = GetComponent<Rigidbody2D>(); _character = GetComponent<CharacterBase>(); _runtimeData = _character.runtimeData; // 自动创建地面检测点(如果忘记设置) if (groundCheck == null) { groundCheck = new GameObject("GroundCheck").transform; groundCheck.SetParent(transform); groundCheck.localPosition = new Vector3(0, -0.5f, 0); } } void FixedUpdate() { // 地面检测 _isGrounded = Physics2D.OverlapCircle( groundCheck.position, groundCheckRadius, groundLayer ); // 绘制检测范围(场景视图可见) Debug.DrawRay(groundCheck.position, Vector2.down * groundCheckRadius, Color.green); } public void Move(float horizontalInput) { // 安全获取移动速度 float moveSpeed = _runtimeData.currentStats.moveSpeed; // 应用移动 _rb.velocity = new Vector2( horizontalInput * moveSpeed, _rb.velocity.y ); } public void Jump() { if (!_isGrounded) return; // 安全获取跳跃力 float jumpForce = _runtimeData.currentStats.jumpForce; // 应用跳跃 _rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse); } public void Dash() { // 修复条件:只能在地面冲刺 && 不在冲刺中 if (_isDashing || !_isGrounded) return; _isDashing = true; _dashTimer = 0.2f; // 冲刺持续时间 // 获取角色朝向 float dashDirection = transform.localScale.x > 0 ? 1 : -1; // 从运行时数据获取速度(修复访问方式) float baseSpeed = _runtimeData.currentStats.moveSpeed; float dashSpeed = baseSpeed * 3f; // 应用冲刺力 _rb.velocity = new Vector2(dashDirection * dashSpeed, 0); } // 结束冲刺方法(修复版) public void EndDash() { _isDashing = false; // 保留部分动量 _rb.velocity = new Vector2(_rb.velocity.x * 0.5f, _rb.velocity.y); } // 可视化地面检测范围 private void OnDrawGizmosSelected() { if (groundCheck == null) return; Gizmos.color = Color.green; Gizmos.DrawWireSphere(groundCheck.position, groundCheckRadius); } // 添加调试信息 void OnGUI() { GUILayout.Label($"冲刺状态: {_isDashing}"); GUILayout.Label($"着地状态: {_isGrounded}"); if (_runtimeData != null) { GUILayout.Label($"移动速度: {_runtimeData.currentStats.moveSpeed}"); } } }
08-11
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值