bzoj 2791 [Poi2012]Rendezvous 倍增lca 基环树

本文介绍了一种处理基环内向树森林问题的方法,包括如何通过倍增LCA来计算同一子树内的距离,以及不同子树间节点的距离计算。通过DFS遍历和预处理,实现了高效的查询。

这是一个基环内向树森林。两个点如果在一个子树中,直接倍增lca。
否则两个点先走到环上,然后一个点不动,另一个点走到这个点。

#include <bits/stdc++.h>
using namespace std;
#define N 510000
int n,q,top,cnt;
int fa[N][21];
int vis[N],st[N],inc[N],root[N],deep[N];
int bel[N],ins[N],num[N],sum[N];
void dfs(int x)
{
    st[++top]=x;vis[x]=ins[x]=1;
    int y=fa[x][0];
    if(ins[y])
    {
        int t=0;
        bel[y]=++cnt;inc[y]=1;num[y]=t;
        fa[y][0]=0;root[y]=y;
        for(int i=top;st[i]!=y;i--)
        {   
            inc[st[i]]=1,bel[st[i]]=cnt;
            root[st[i]]=st[i];num[st[i]]=++t;
            fa[st[i]][0]=0;
        }
        sum[cnt]=t+1;ins[x]=0;
        return;
    }
    if(!vis[y])dfs(y);
    ins[x]=0;
    if(inc[x])return;
    bel[x]=bel[y];deep[x]=deep[y]+1;
    root[x]=root[y];
    for(int i=1;i<=20;i++)
        fa[x][i]=fa[fa[x][i-1]][i-1];
}
int lca(int x,int y)
{
    if(deep[x]<deep[y])swap(x,y);
    for(int i=20;i>=0;i--)
        if(deep[fa[x][i]]>=deep[y])
            x=fa[x][i];
    if(x==y)return x;
    for(int i=20;i>=0;i--)
        if(fa[x][i]!=fa[y][i])
            x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}
int main()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)
        scanf("%d",&fa[i][0]);
    for(int i=1;i<=n;i++)
        if(!vis[i]){top=0;dfs(i);}
    for(int a,b,x,y;q--;)
    {
        scanf("%d%d",&a,&b);
        if(bel[a]!=bel[b])
            {puts("-1 -1");continue;}
        if(root[a]==root[b])
        {
            int t=lca(a,b);
            x=deep[a]-deep[t],y=deep[b]-deep[t];
            printf("%d %d\n",x,y);
        }
        else
        {
            x=deep[a];y=deep[b];
            a=root[a];b=root[b];
            int m=sum[bel[a]];
            int x1=x+(num[a]-num[b]+m)%m,y1=y;
            int x2=x,y2=y+(num[b]-num[a]+m)%m;
            int mx1=max(x1,y1),mx2=max(x2,y2),mn1=min(x1,y1),mn2=min(x2,y2);
            if(mx1<mx2||(mx1==mx2&&mn1<mn2)||(mx1==mx2&&mn1==mn2&&x1>=y1))
                printf("%d %d\n",x1,y1);
            else printf("%d %d\n",x2,y2);
        }
    }
    return 0;
}
<think>我们正在解决用户遇到的C++编译错误:error: 'conjunction' is not a member of 'std' 根据错误信息,这通常是因为编译器不支持C++17标准或未启用C++17模式。'std::conjunction'是C++17引入的模板元编程工具。 解决方案: 1. 确保编译器支持C++17:检查编译器版本(如GCC>=7, Clang>=5, MSVC>=19.15等)。 2. 在编译时启用C++17标准:对于GCC/Clang,使用编译选项`-std=c++17`;对于MSVC,使用`/std:c++17`。 另外,如果由于项目限制不能使用C++17,可以考虑使用替代方案: - 使用`std::enable_if`和`std::conditional`等组合来模拟`std::conjunction`的功能。 - 或者自定义一个`conjunction`实现(注意:需要确保与标准库中的行为一致,避免冲突)。 参考引用: [^1]中提到的错误是关于`std::function`的,但问题不同,不过它提醒我们检查编译器版本和标准库支持。 [^3]中提到的`std::shared_from_this`是C++11特性,但这里不直接相关,不过它展示了C++标准库特性的版本依赖性。 因此,我们主要建议用户检查编译器版本和启用C++17标准。 生成相关问题: 1. 如何检查我的编译器支持的C++标准? 2. 如何在CMake项目中设置C++17标准? 3. 如果无法升级编译器,如何实现类似`std::conjunction`的功能?</think>### 解决 C++ 编译错误:`error: 'conjunction' is not a member of 'std'` #### 问题原因 `std::conjunction` 是 C++17 标准引入的**模板元编程工具**,用于在编译时判断多个布尔条件的逻辑与(AND)。此错误通常由以下原因导致: 1. **编译器未启用 C++17 模式**:默认使用旧标准(如 C++14/C++11)。 2. **编译器版本过低**:GCC < 7.1 / Clang < 5.0 / MSVC < 19.15(VS 2017 15.8+)不支持该特性[^3]。 3. **标准库缺失或配置错误**:如链接了旧版 libstdc++ 或 libc++。 --- #### 解决方案 ##### 方法 1:启用 C++17 编译模式 在编译命令中添加对应的标准标识符: ```bash # GCC/Clang g++ -std=c++17 your_file.cpp -o output # MSVC (Visual Studio) 设置项目属性 → C/C++ → 语言 → C++语言标准 → 选择 "ISO C++17 标准" ``` ##### 方法 2:升级编译器 - **GCC**:升级至 ≥7.1([下载地址](https://gcc.gnu.org/)) - **Clang**:升级至 ≥5.0([下载地址](https://releases.llvm.org/)) - **MSVC**:升级至 Visual Studio 2017 (15.8+) 或更高版本 ##### 方法 3:手动实现替代方案(兼容 C++11) 若无法升级编译器,可自定义 `conjunction`: ```cpp #include <type_traits> // 兼容 C++11 的 conjunction 实现 template <typename...> struct conjunction : std::true_type {}; template <typename B1> struct conjunction<B1> : B1 {}; template <typename B1, typename... Bn> struct conjunction<B1, Bn...> : std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {}; ``` --- #### 验证示例 启用 C++17 后,以下代码应正常编译: ```cpp #include <type_traits> int main() { static_assert(std::conjunction_v<std::true_type, std::true_type>); // 编译通过 return 0; } ``` --- #### 技术背景 `std::conjunction` 属于 `<type_traits>` 库,常用于模板约束或 SFINAE 场景。其实现依赖于 C++17 的**折叠表达式**和**模板变量**特性,例如: ```cpp template <class... B> struct conjunction : std::bool_constant<(B::value && ...)> {}; ``` 此机制通过共享的控制块(control block)管理类型逻辑[^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值