[CodeChef May Challenge 2018]Edges in Spanning Trees

解决两棵树间的边匹配问题,通过遍历与线段树合并维护等算法优化,实现高效查询,复杂度达到O(nlogn)。

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

Description

给出两棵树,T1和T2
对于T1中的每一条边e1,你需要求出T2中有多少条边e2满足
1:T1-e1+e2是一棵树
2:T2-e2+e1是一棵树
n<=2e5

Solution

我们考虑一组限制的两种方法,并且这两种方法能够套在一起
首先,我们知道可以对于T2中的每一条边(u,v),在第一棵树上的u,v打上标记,在lca(u,v)处撤销
这样子我们可以在遍历的时候求出那些e2边可能满足条件
接下来对于每个e1(x,y)满足条件的e2需要存在在T2中x到y的路径上
也就是我们需要满足单点修改,路径询问,然后用线段树合并维护
这个并没有必要用树链剖分,可以直接括号序维护
复杂度O(n log n)

Code

#include <cmath>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define rep(i,a,b) for(int i=lst[b][a];i;i=nxt[i])
using namespace std;

typedef vector<int> vec;
#define pb(a) push_back(a)

int read() {
    char ch;
    for(ch=getchar();ch<'0'||ch>'9';ch=getchar());
    int x=ch-'0';
    for(ch=getchar();ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
    return x;
}

void write(int x) {
    if (!x) {putchar('0');putchar(' ');return;}
    char ch[20];int tot=0;
    for(;x;x/=10) ch[++tot]=x%10+'0';
    fd(i,tot,1) putchar(ch[i]);
    putchar(' ');
}

const int N=4e5+5;

int t[N<<1],nxt[N<<1],lst[2][N],l;
void add(int x,int y,int a) {
    t[++l]=y;nxt[l]=lst[a][x];lst[a][x]=l;
}

int n,dfn[2][N],fir[2][N],dep[2][N],tot,f[2][N][19],lg[N];

void dfs(int x,int y,int a) {
    dfn[a][++tot]=x;fir[a][x]=tot;dep[a][x]=dep[a][y]+1;
    rep(i,x,a) if (t[i]!=y) dfs(t[i],x,a),dfn[a][++tot]=x;
}

int lca(int x,int y,int a) {
    x=fir[a][x];y=fir[a][y];
    if (x>y) swap(x,y);
    int z=lg[y-x+1];
    x=f[a][x][z];y=f[a][y-(1<<z)+1][z];
    return dep[a][x]<dep[a][y]?x:y; 
}

int in[N],out[N];

void travel(int x,int y) {
    in[x]=++tot;
    rep(i,x,1) if (t[i]!=y) travel(t[i],x);
    out[x]=++tot;
}

int u1[N],u2[N],v1[N],v2[N],an[N];
vec q[N];

int tr[N<<5],ls[N<<5],rs[N<<5],rt[N],cnt;

void modify(int &v,int l,int r,int x,int y) {
    if (!v) v=++cnt;
    if (l==r) {tr[v]+=y;return;}
    int mid=l+r>>1;
    if (x<=mid) modify(ls[v],l,mid,x,y);
    else modify(rs[v],mid+1,r,x,y);
    tr[v]=tr[ls[v]]+tr[rs[v]];
}

int merge(int x,int y,int l,int r) {
    if (!x||!y) return x+y;
    if (l==r) {tr[x]+=tr[y];return x;}
    int mid=l+r>>1;
    ls[x]=merge(ls[x],ls[y],l,mid);
    rs[x]=merge(rs[x],rs[y],mid+1,r);
    tr[x]=tr[ls[x]]+tr[rs[x]];
    return x;
}

int query(int v,int l,int r,int x,int y) {
    if (!v) return 0;
    if (l==x&&r==y) return tr[v];
    int mid=l+r>>1;
    if (y<=mid) return query(ls[v],l,mid,x,y);
    else if (x>mid) return query(rs[v],mid+1,r,x,y);
    else return query(ls[v],l,mid,x,mid)+query(rs[v],mid+1,r,mid+1,y);
}

void solve(int x,int y) {
    rep(i,x,0) if (t[i]!=y) solve(t[i],x);
    rep(i,x,0) rt[x]=merge(rt[x],rt[t[i]],1,tot);
    if (!q[x].empty())
        fo(i,0,q[x].size()-1) {
            int z=q[x][i];
            if (z>0) modify(rt[x],1,tot,in[z],1),modify(rt[x],1,tot,out[z],-1);
            else modify(rt[x],1,tot,in[-z],-1),modify(rt[x],1,tot,out[-z],1);
        }
    if (y) {
        int z=lca(x,y,1);
        an[x]=query(rt[x],1,tot,1,in[x])+query(rt[x],1,tot,1,in[y])-2*query(rt[x],1,tot,1,in[z]);
    }
}

int main() {
    for(int ty=read();ty;ty--) {
        n=read();
        memset(lst,0,sizeof(lst));l=0;
        fo(i,1,n-1) {
            u1[i]=read();v1[i]=read();
            add(u1[i],v1[i],0);add(v1[i],u1[i],0);
        }
        fo(i,1,n-1) {
            u2[i]=read();v2[i]=read();
            add(u2[i],v2[i],1);add(v2[i],u2[i],1);
        }
        tot=0;dfs(1,0,0);
        tot=0;dfs(1,0,1);
        fo(a,0,1) fo(i,1,tot) f[a][i][0]=dfn[a][i];
        fo(i,1,tot) lg[i]=log(i)/log(2);
        fo(a,0,1)
            fo(j,1,18)
                fo(i,1,tot-(1<<j)+1) {
                    int x=f[a][i][j-1],y=f[a][i+(1<<j-1)][j-1];
                    f[a][i][j]=dep[a][x]<dep[a][y]?x:y;
                }
        tot=0;travel(1,0);
        fo(i,1,cnt) tr[i]=ls[i]=rs[i]=0;cnt=0;
        fo(i,1,n) q[i].clear(),rt[i]=0;
        fo(i,1,n-1) {
            int x=u2[i],y=v2[i],z=lca(x,y,0);
            int val=dep[1][x]<dep[1][y]?y:x;
            q[x].pb(val);q[y].pb(val);
            q[z].pb(-val);q[z].pb(-val);
        }
        solve(1,0);
        fo(i,1,n-1) {
            int x=u1[i],y=v1[i];
            write(dep[0][x]<dep[0][y]?an[y]:an[x]);
        }
        puts("");
    }
    return 0;
} 
<think>好的,我现在需要解决用户遇到的错误:'Graph' object has no attribute 'in_edges'。首先,用户可能在使用某个图处理库时调用了in_edges方法,但该属性不存在。我需要逐步分析可能的原因和解决方案。 首先,我应该确定用户使用的图库是什么。常见的Python图处理库有NetworkX、igraph、graph-tool等。不同的库有不同的API设计。比如,NetworkX中的DiGraph有in_edges方法,而普通的Graph可能没有,因为无向图没有入边的概念。如果用户错误地在无向图上调用in_edges,就会导致这个错误。 接下来,假设用户使用的是NetworkX。检查是否正确创建了有向图(DiGraph),而不是无向图(Graph)。如果用户创建的是无向图,调用in_edges自然会报错,因为无向图的边没有方向,所有边都是双向的,所以没有入边和出边的区分。这时候需要确认图类型是否为DiGraph。 另一个可能性是拼写错误或者版本问题。例如,某些库的旧版本可能没有in_edges方法,或者方法名有大小写不同。需要让用户检查库的版本,并确认文档中是否存在该方法。 如果是igraph库,它的边处理方式不同,可能没有直接的in_edges方法,而是通过其他方式获取入边,比如使用vs对象的in_edges()方法。这时候需要用户调整代码,先选择节点再获取入边。 可能的解决方案步骤: 1. 确认使用的图类型是否正确,是否为有向图。 2. 检查图库的文档,确认in_edges方法的存在和正确用法。 3. 如果是NetworkX,将图对象改为DiGraph,并使用in_edges方法。 4. 如果是igraph,使用适当的方法获取入边。 5. 检查库的版本,必要时升级到最新版本。 需要提醒用户注意不同库之间的API差异,并确保使用的方法与图类型匹配。另外,建议用户查看错误发生的代码行,确认图对象的创建方式和方法调用是否正确。如果可能,提供示例代码片段会有助于更准确地诊断问题。</think>遇到 `'Graph' object has no attribute 'in_edges'` 错误时,通常是因为代码中使用的图(Graph)对象不支持 `in_edges` 方法。以下是逐步分析和解决方案: --- ### **1. 确认图类型** `in_edges` 方法通常用于 **有向图**(Directed Graph)中获取节点的入边。若你使用的是无向图(Undirected Graph),则此方法不存在。 - **常见库的图类型命名**: - **NetworkX**: - 无向图:`nx.Graph()` - 有向图:`nx.DiGraph()`(需使用 `DiGraph` 才有 `in_edges`) - **igraph**:通过 `directed=True` 参数创建有向图。 - **graph-tool**:通过 `g = Graph(directed=True)` 创建有向图。 **解决方法**: 检查创建图的代码,确保使用的是有向图类型。 --- ### **2. 检查库的API** 不同图处理库的API设计不同: #### **NetworkX 示例** ```python import networkx as nx # 错误:无向图没有 in_edges G = nx.Graph() G.add_edge(1, 2) print(G.in_edges(1)) # 报错 # 正确:使用有向图 G = nx.DiGraph() G.add_edge(1, 2) print(G.in_edges(1)) # 输出:[(2, 1)](假设边是 2 -> 1) ``` #### **igraph 示例** igraph 中获取入边的方式不同: ```python from igraph import Graph g = Graph(directed=True) g.add_vertices(2) g.add_edge(1, 0) # 边是 1 -> 0 # 获取节点0的入边(指向0的边) in_edges = g.vs[0].in_edges() ``` **解决方法**: 查阅对应库的文档,确认 `in_edges` 的使用方式。 --- ### **3. 升级库版本** 某些旧版本图处理库可能未实现 `in_edges` 方法。尝试升级到最新版本: ```bash pip install --upgrade networkx # 以NetworkX为例 ``` --- ### **4. 替代方法** 如果库不支持 `in_edges`,可通过其他方式获取入边。例如在无向图中,所有边均视为双向: ```python # 无向图中,所有边都是双向的 G = nx.Graph() G.add_edge(1, 2) print(G.edges(1)) # 输出:[(1, 2)] ``` --- ### **总结** 1. **确认图是有向的**(如 `nx.DiGraph()`)。 2. **查阅库的文档**,确认 `in_edges` 是否可用。 3. **升级库版本**。 4. 若问题未解决,提供代码片段和库版本,以便进一步诊断。 若有更多细节(如代码片段),可进一步分析具体原因!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值