版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40032278/article/details/81539251
http://codeforces.com/problemset/problem/191/C
题目
给出一棵n个节点的树,还有树上的k条简单路径(用路径的两个端点u和v表示),求树上的各条边被这些简单路径经过的总次数。
题解
只要记录一下每个节点i到根节点路径上所有边都需要加的权值sum[i]就行了。
对于每一组(u,v),题意操作转化为 c[u]++ , a[v]++ , a[ lca(u,v) ] - =2。
最后用一遍dfs把sum拆开
#include<bits/stdc++.h>
using namespace std;
int to[400010],h1[400010],h2[400010],cnt,next[400010];
int f[400010],a[400010],c[400010];
void add(int head[],int u,int vv)
{
cnt++;
to[cnt]=vv;
next[cnt]=head[u];
head[u]=cnt;
}
int find(int x)
{
return x==f[x]?x:f[x]=find(f[x]);
}
void ddd(int x)
{
f[x]=x;
for(int i=h2[x]; i!=0; i=next[i])
{
a[x]++;
if(f[to[i]]) a[find(to[i])]-=2;
}
for(int i=h1[x]; i!=0; i=next[i])
{
if(f[to[i]]==0)
{
ddd(to[i]);
a[x]+=c[i+1>>1]=a[to[i]];
f[to[i]]=x;
}
}
}
int main()
{
// freopen("a.txt","r",stdin);
int n,i,m,x,y;
cnt=0;
scanf("%d",&n);
for(i=1; i<n; i++)
{
scanf("%d%d",&x,&y);
add(h1,x,y);
add(h1,y,x);
}
scanf("%d",&m);
for(i=1; i<=m; i++)
{
scanf("%d%d",&x,&y);
if(x==y) continue;
add(h2,x,y);
add(h2,y,x);
}
ddd(1);
for(i=1; i<n; i++) printf("%d ",c[i]);
return 0;
}