AtCoder Beginner Contest 152 - F - Tree and Constraints (容斥定理+树上路径的性质)
We have a tree with NN vertices numbered 11 to NN. The ii-th edge in this tree connects Vertex aiai and Vertex bibi.
Consider painting each of these edges white or black. There are 2N−12N−1 such ways to paint the edges. Among them, how many satisfy all of the following MM restrictions?
- The ii-th (1≤i≤M)(1≤i≤M) restriction is represented by two integers uiui and vivi, which mean that the path connecting Vertex uiui and Vertex vivi must contain at least one edge painted black.
题意:
给定一个含有n个节点的树,每一条边可以给其染成黑色或者白色。
还有m个限制条件,每一个限制条件包括两个节点(u,v),限制为(u,v)节点之间的路径中必须包含至少一个涂成黑色的边。
问有多少种染色方法使其同时满足m个条件。
思路:
答案(ans=v1-v2)
(v1)代表所有染色方案,(v2)代表不满足条件的染色方案
我们知道(v1=2^{n-1}),
那么问题就直接转换成了求(v2)
设(A_i)代表不满足第i个限制条件的方案数,那么(v2)就等于(A_i)的并集,即(v2=igcup_1^{m} A_i)。
根据容斥定理:
那么我们就可以直接枚举(m)个限制的所有集合来求出(v2)。
那么问题来了,怎么求(A_i)呢?
(path_j)代表从根节点(无根树的话就假定一个根)到第(j)个节点经过了哪些边。
因为(nleq 50),所以(path_i)我们采用$long long $ 数据类型进行二进制状态压缩表示。
那么节点(x,y)之间的路径经历的边信息(info=path_x oplus path_y),(oplus) 是抑或符号。
那么对于枚举的每一个集合(i),把包含的所有限制的边信息(info)或起来后计算有多少个边,假设个数为(num)。
那么这(num)个边染成白色时集合(i)才不满足条件。那么剩下(free=n-1-num)个边可以自由染色。
直接根据奇偶判断在容斥定理中公式的正负号即可。
代码:
int n;
int m;
std::vector<int> v[maxn];
ll path[maxn];
void dfs(int x, int pre, ll num)
{
path[x] = num;
for (auto y : v[x])
{
if (y == pre)
{
continue;
}
dfs(y, x, num | (1ll << y));
}
}
ll info[maxn];
int main()
{
//freopen("D:\code\text\input.txt","r",stdin);
//freopen("D:\code\text\output.txt","w",stdout);
n = readint();
repd(i, 1, n - 1)
{
int x = readint();
int y = readint();
v[x].push_back(y);
v[y].push_back(x);
}
dfs(1, 0, 0ll);
m = readint();
repd(i, 0, m - 1)
{
int x = readint();
int y = readint();
info[i] = (path[x] ^ path[y]);
}
int maxstate = (1 << m) - 1;
ll ans = 0ll;
repd(i, 0, maxstate)
{
ll num = 0ll;
int cnt = 0;
repd(j, 0, m - 1)
{
if (i & (1 << j)) {
cnt++;
num |= info[j];
}
}
int free = n - 1 - __builtin_popcountll(num);
ans += poww(2ll, free) * (cnt & 1 ? -1ll : 1ll);
}
printf("%lld
", ans);
return 0;
}