今天练了贪心算法
发道难题
Imakf 是一个小蒟蒻,他最近刚学了 LCA,他在手机 APPstore 里看到一个游戏也叫做 LCA 就下载了下来。
题目描述
这个游戏会给出你一棵树,这棵树有 NN 个节点,根结点是 RR ,系统会选中 MM 个点 P_1,P_2…P_MP
1
,P
2
…P
M
,要Imakf 回答有多少组点对 (u_i,v_i)(u
i
,v
i
) 的最近公共祖先是 P_iP
i
。Imakf 是个小蒟蒻,他就算学了 LCA 也做不出,于是只好求助您了。
Imakf 毕竟学过一点 OI,所以他要求您把答案模 (10^9+7)(10
9
+7)。
输入格式
第一行 N , R , MN,R,M
此后 N-1N−1 行 每行两个数 a,ba,b 表示 a,ba,b 之间有一条边。
此后 11行,共 MM 个数,表示P_iP
i
题面链接:https://www.luogu.com.cn/problem/P5002
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define maxn (100000+3)
#define mod (1000000007)
long long head[maxn],tot;
struct edge {
long long node,next;
} h[maxn<<1];
void addedge(long long u,long long v) {
h[++tot].next=head[u];
head[u]=tot;
h[tot].node=v;
}
long long n,r,m;
long long son[maxn],fa[maxn],ans[maxn];
void dfs(long long now,long long f) { //树剖常规操作,预处理size,fa,son
fa[now]=f;
son[now]=1;
for(register long long i=head[now]; i; i=h[i].next) {
long long d=h[i].node;
if(d==f) continue;
dfs(d,now);
son[now]+=son[d];
}
}
long long solve(long long now) {
if(ans[now]) return ans;
long long sigma=0,chengji=0;
for(register long long i=head[now]; i; i=h[i].next) {
long long d=h[i].node;
if(d==fa[now]) continue;
sigma+=son[d];
sigma%=mod;
chengji+=son[d]*son[d];
chengji%=mod;
}
return ans[now]=(son[now]*2%mod-1+sigma*sigma%mod-chengji+mod)%mod;
}
int main() {
scanf("%lld%lld%lld",&n,&r,&m);
for(register long long i=1,u,v; i<n; ++i) {
scanf("%lld%lld",&u,&v);
addedge(u,v);
addedge(v,u);
}
dfs(r,0);
for(register long long i=1,p; i<=m; ++i) {
scanf("%lld",&p);
printf("%lld\n",solve(p));
}
return 0;
}