CF575B Bribes(树上差分)
注意这里的差分是有向的,diff[0]代表从该点出发的覆盖, diff[1]代表从该点进入的覆盖,但是树上差分都是表示一个点到根节点(最后统计前缀和的这种顺序),详细可以看神仙ChPu437的勃客
贴个本蒟蒻的代码qwq
inline int qpow(int a,int b){
int res = 1;
for(;b;b >>= 1){
if(b & 1) res = 1ll * res * a % mod;
a = 1ll*a * a % mod;
} return res;
}
struct edge{int from,to,next;bool f;}e[N<<1]; int head[N],tot;
inline void add(int u,int v,bool f){
e[++tot] = (edge){u,v,head[u],f}; head[u] = tot;
}
int n,m,a[N],diff[2][N];
int fa[N],son[N],siz[N],dep[N],top[N];
void dfs1(int x,int f){
fa[x] = f; siz[x] = 1;
for(int i = head[x];i;i = e[i].next){
int v = e[i].to;
if(v == f) continue; dep[v] = dep[x] + 1;
dfs1(v,x); siz[x] += siz[v];
if(siz[son[x]] < siz[v]) son[x] = v;
}
}
void dfs2(int x,int tp){
top[x] = tp;
if(son[x]) dfs2(son[x],tp);
for(int i = head[x];i;i = e[i].next){
int v = e[i].to;
if(v == fa[x] || v == son[x]) continue;
dfs2(v,v);
}
}
int lca(int x,int y){
while(top[x] != top[y]){
if(dep[top[x]] < dep[top[y]]) swap(x,y);
x = fa[top[x]];
}
if(dep[x] > dep[y]) swap(x,y);
return x;
}
void solve(int x,int f){
for(int i = head[x];i;i = e[i].next){
int v = e[i].to;
if(v == f) continue;
solve(v,x);
diff[0][x] += diff[0][v];
diff[1][x] += diff[1][v];
}
}
int main(){
n = read();int u,v; bool f;
for(int i = 1;i < n;++i){
u = read(); v = read(); f = read();
add(u,v,f); add(v,u,f);
}
dfs1(1,0); dfs2(1,1);
int k = read(); int s = 1,t;
for(int i = 1;i <= k;++i){
t = read(); int LCA = lca(s,t);
++diff[0][s]; --diff[0][LCA];
++diff[1][t]; --diff[1][LCA]; s = t;
}
solve(1,0); long long ans = 0;
for(int i = 1;i <= tot;i += 2){
if(!e[i].f) continue;
u = e[i].from; v = e[i].to;
int cnt = dep[u] > dep[v] ? diff[1][u] : diff[0][v];
ans = ((ans + qpow(2,cnt)) % mod - 1 + mod) % mod;
}
printf("%lld",ans);
}