CF575B

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);
}
posted @ 2020-10-20 10:27  INFP  阅读(239)  评论(0编辑  收藏  举报