[树的直径] Codechef March Cook-Off 2018. Maximum Tree Path

本文介绍了一道计蒜之道中的图论题目解法,通过枚举最大公约数(gcd),并使用并查集维护图中连通块的直径来求解。详细解释了如何对边进行排序和处理,以便于高效地更新答案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这个套路好像是计蒜之道里的一题

考虑枚举gcd

把两端点都是gcd的倍数的边存下来,按照两段点较小值从大到小排序

枚举每一条边,把这条边加入图中,可以用并查集维护出所有联通块的直径,然后就好了

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#define fi first
#define se second

using namespace std;

typedef long long ll;
typedef pair<int,int> pii;

const int N=200010;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}

inline void read(int &x){
  char c=nc(); x=0;
  for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}

int T,n,cnt,G[N],a[N];
struct edge{
  int t,nx,w;
}E[N<<1];

inline void addedge(int x,int y,int w){
  E[++cnt].t=y; E[cnt].nx=G[x]; E[cnt].w=w; G[x]=cnt;
  E[++cnt].t=x; E[cnt].nx=G[y]; E[cnt].w=w; G[y]=cnt;
}

vector<pii> ed[N];

ll cst[N];
int dpt[N],dfsl[N],p[N],t;

void dfs(int x,int f){
  dpt[x]=dpt[f]+1;
  dfsl[++t]=x; p[x]=t;
  for(int i=G[x];i;i=E[i].nx)
    if(E[i].t!=f){
      cst[E[i].t]=cst[x]+E[i].w;
      dfs(E[i].t,x);
      dfsl[++t]=x;
    }
}

#define Min(x,y) (dpt[x]<dpt[y]?x:y)

int lgt[N],st[N][20];

inline void Pre(){
  for(int i=1;i<=t;i++) lgt[i]=lgt[i-1]+((1<<lgt[i-1]+1)==i);
  for(int i=1;i<=t;i++) st[i][0]=dfsl[i];
  for(int k=1;k<=lgt[t];k++)
    for(int i=1;i+(1<<k)-1<=t;i++)
      st[i][k]=Min(st[i][k-1],st[i+(1<<k-1)][k-1]);
}

inline int lca(int x,int y){
  x=p[x]; y=p[y];
  if(x>y) swap(x,y);
  int t=lgt[y-x+1];
  return Min(st[x][t],st[y-(1<<t)+1][t]);
}

inline ll dist(int x,int y){
  return cst[x]+cst[y]-2*cst[lca(x,y)];
}

inline bool cmp(pii x,pii y){
  return a[x.fi]<a[y.fi];
}

int fa[N],l[N],r[N];

int getfa(int x){
  return x==fa[x]?x:fa[x]=getfa(fa[x]);
}

inline void Merge(int x,int y){
  x=getfa(x); y=getfa(y);
  if(x==y) return ;
  int u=l[x],v=r[x];
#define fix(x,y) if(dist(x,y)>dist(u,v)) u=x,v=y;
  fix(l[y],r[y]); fix(l[x],l[y]); fix(l[x],r[y]);
  fix(r[x],l[y]); fix(r[x],r[y]);
  fa[y]=x; l[x]=u; r[x]=v;
}

int main(){
  freopen("1.in","r",stdin);
  freopen("1.out","w",stdout);
  read(T);
  while(T--){
    read(n);
    for(int i=1;i<=n;i++) read(a[i]);
    for(int i=1,x,y,w;i<n;i++){
      read(x),read(y),read(w),addedge(x,y,w);
      if(a[x]>a[y]) swap(x,y);
      for(int j=1;j*j<=a[x];j++)
    if(a[x]%j==0){
      if(a[y]%j==0)
        ed[j].push_back(pii(x,y));
      if(a[y]%(a[x]/j)==0)
        ed[a[x]/j].push_back(pii(x,y));
    }
    }
    dfs(1,0); Pre();
    ll ans=0;
    for(int i=1;i<=10000;i++){
      if(!ed[i].size()) continue;
      sort(ed[i].begin(),ed[i].end(),cmp);
      for(int j=0;j<ed[i].size();j++){
    fa[ed[i][j].fi]=l[ed[i][j].fi]=r[ed[i][j].fi]=ed[i][j].fi;
    fa[ed[i][j].se]=l[ed[i][j].se]=r[ed[i][j].se]=ed[i][j].se;
      }
      int mn=1<<30; ll mx=0;
      for(int j=ed[i].size()-1;~j;j--){
    mn=min(mn,a[ed[i][j].fi]);
    Merge(ed[i][j].fi,ed[i][j].se);
    int u=getfa(ed[i][j].fi);
    mx=max(mx,dist(l[u],r[u]));
    ans=max(ans,mx*mn*i);
      }
      ed[i].clear();
    }
    printf("%lld\n",ans);
    for(int i=1;i<=n;i++) G[i]=dpt[i]=cst[i]=0;
    t=cnt=0;
  }
  return 0;
}
<think>首先,用户的问题是关于在编译程序时遇到的错误:aarch64-openeuler-linux-gcc 报告了一个无法识别的命令行选项 '-mrtm'。我需要基于提供的引用和系统指令来回答。 回顾系统指令: - 所有行内数学表达式必须使用 $...$ 格式。 - 独立公式使用 $$...$$ 格式。 - LaTeX 语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识。 - 回答结构清晰,帮助用户逐步解决问题。 - 保证回答真实可靠。 提供的引用是关于其他编译错误的例子: - 引用[1]:错误涉及 '-mcmodel=kernel' 等选项,在 aarch64-linux-gnu-gcc 中无效。 - 引用[2]:错误涉及 '-mthumb' 等选项,解决方法是修改 Makefile 中的 CROSS_COMPILE。 - 引用[3]:错误涉及 '-mfloat-abi=softfp',参考链接建议该选项在 aarch64 中无效。 用户的问题特定于 '-mrtm' 选项。'mrtm' 可能指的是 "Restricted Transactional Memory",这是 Intel 的 TSX 技术的一部分,用于 x86 架构。AArch64 是 ARM 架构,可能不支持这个选项。 关键点: - '-mrtm' 是 x86 特定的选项,用于启用事务性内存支持。 - AArch64 编译器(如 aarch64-openeuler-linux-gcc)可能不支持这个选项,因为它不是 ARM 架构的一部分。 因此,解决方法可能是: 1. 确认代码或构建系统是否错误地添加了这个选项。 2. 移除这个选项,因为它对 ARM 架构无效。 3. 检查是否有替代选项或是否需要修改代码来适应 ARM。 参考引用中的模式: - 在引用[1]中,错误是由于无效选项导致的,建议检查选项有效性。 - 在引用[2]中,通过修改 Makefile 解决了问题。 - 在引用[3]中,选项 '-mfloat-abi=softfp' 在 aarch64 中无效,建议移除或使用其他选项。 所以,对于用户的问题,我应该: - 解释为什么这个选项无效。 - 建议如何移除或替换这个选项。 - 提供逐步解决方法。 结构化回答: 1. **问题分析**:解释错误原因。 2. **解决方案**:给出具体步骤。 3. **生成相关问题**:在最后添加。 使用中文回答。 确保引用:由于用户提供了引用,我需要在回答中自然地引用它们,如果相关。但用户的问题是基于这些引用,所以我可以参考它们。 用户说:"上述引用仅供参考,并不是用户真正的需求",所以焦点是当前问题。 最终回答结构: - 开头:确认问题。 - 分析:为什么出现错误。 - 解决步骤:如何修复。 - 结尾:生成相关问题。</think>### 问题分析 您在编译程序时遇到的错误 `aarch64-openeuler-linux-gcc: error: unrecognized command-line option '-mrtm'`,表明编译器无法识别 `-mrtm` 选项。这个选项是用于启用 **Restricted Transactional Memory (RTM)** 的,它主要针对 **x86 架构**(如 Intel TSX 技术),用于优化事务性内存操作。然而,您使用的 `aarch64-openeuler-linux-gcc` 是针对 **AArch64(ARMv8)架构**的编译器,该架构不支持 RTM 功能。因此,这个选项在 ARM 环境中无效,导致编译失败。类似问题在其他架构迁移中也常见,如引用中提到的无效选项 `-mcmodel=kernel` 或 `-mfloat-abi=softfp`,这些选项在 AArch64 编译器中不被识别[^1][^3]。 ### 解决方法 要解决此问题,您需要从构建配置中移除或替换 `-mrtm` 选项。以下是逐步操作指南,确保编译过程顺利: 1. **识别并移除无效选项**: - 检查您的 Makefile、CMakeLists.txt 或编译脚本,找到包含 `-mrtm` 的代码行。 - 直接删除该选项。例如,如果编译命令类似于: ```bash aarch64-openeuler-linux-gcc -O2 -mrtm -o output source.c ``` 修改为: ```bash aarch64-openeuler-linux-gcc -O2 -o output source.c ``` - 如果您不确定选项来源,使用 `grep` 命令搜索项目文件: ```bash grep -r "-mrtm" /path/to/your/project ``` 2. **检查代码兼容性**: - `-mrtm` 通常用于优化多线程代码(如使用 `_xbegin()` 或 `_xend()` 指令)。在 ARM 架构中,您需要替换为等效机制: - 使用 ARM 的原子操作(如 `__atomic` 内置函数)或锁-free 编程。 - 如果代码严重依赖 x86 特定特性,考虑重写相关部分以兼容 AArch64。 - 例如,将事务性内存代码替换为 ARM 的 NEON SIMD 指令或标准锁机制(如 pthread 互斥锁)。 3. **验证编译器支持**: - 运行 `aarch64-openeuler-linux-gcc --help` 查看支持的选项列表,确认 `-mrtm` 不在其中。 - 确保您的编译环境针对 AArch64 正确配置。参考引用[2]中的方法,检查 Makefile 中的 `CROSS_COMPILE` 设置是否指向正确的工具链(如 `aarch64-openeuler-linux-`)[^2]。 4. **测试修复**: - 移除选项后重新编译: ```bash make clean make ``` - 如果错误消失,表明问题已解决。如果仍有其他错误,检查是否有类似无效选项(如 `-mno-sse` 或 `-m64`),并逐一移除[^1]。 如果问题源于第三方库或依赖,更新库版本或应用补丁以移除架构特定选项。参考引用[3]的链接,ARM 社区建议避免使用 x86 专属选项,而是使用标准 C/C++ 代码确保跨平台兼容性[^3]。 ### 根本原因和预防 - **原因**:`-mrtm` 是 x86 特有选项,在 ARM 的 GCC 工具链中无效。这通常发生在将 x86 代码移植到 ARM 时未清理构建配置。 - **预防**:在跨平台开发中,始终使用条件编译(如 `#ifdef __x86_64__`)隔离架构相关选项,并定期检查编译器文档。 ### 相关问题 1. 如何检测和移除 AArch64 编译中的其他无效选项(如 `-mno-sse`)? 2. 在 ARM 架构下,如何实现事务性内存的替代方案以提高性能? 3. 如何配置 OpenEuler 的交叉编译工具链以避免类似错误?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值