Magic_World
2022-11-09 19:25:28
对于一棵
设第
这并不好求,但都能转化到这个形式了,丰富的经验告诉我们这是一道容斥题。
转化:
后半段式子根据容斥公式转化为:
为了使问题更直观,将限制条件状态压缩,若第
设
于是我们求出所有
现在思考如何求每个
发现
则我们只需要直到多少边必须是白色即可,这相当于求出这些路径的并集有多少边。
发现
设
设
则根据经典的树上异或性质:
求出
设这个数为
最终答案为
注意细节!!!
__builtin_popcountll
。#include<bits/stdc++.h>
#define rep(i,a,n) for(int i=a;i<=n;++i)
#define int long long
using namespace std;
const int N = 51,M = 21;
int n,m,path[N],info[M];
struct EDGE{int to,nxt;}e[N<<1];
int h[N],qcnt;
void adedge(int x,int y){e[++qcnt] = (EDGE){y,h[x]},h[x]=qcnt;}
void dfs(int x,int fa)
{
for(int i=h[x];i;i=e[i].nxt)
{
int v = e[i].to;
if(v==fa) continue;
path[v] = path[x] | (1ll<<v);
dfs(v,x);
}
}
// 64 位使用 __builtin_popcountll() !!!
int f(int S)
{
int edge=0ll,num = __builtin_popcountll(S);
rep(i,0,m-1) if(S&(1ll<<i))
edge |= info[i+1];
return (1ll<<(n - 1 - __builtin_popcountll(edge)))*(num&1 ? 1ll : -1ll);
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n;
rep(i,1,n-1) {
int x,y; cin>>x>>y;
adedge(x,y),adedge(y,x);
}
dfs(1,0);
cin>>m;
int U = (1ll<<m)-1;
rep(i,1,m)
{
int x,y; cin>>x>>y;
info[i] = path[x]^path[y];
}
int ans=0ll;
rep(S,1,U) // S = 0 的情况就是全集本身
{
ans += f(S);
}
int uans = (1ll<<(n-1));
cout<<uans-ans;
return 0;
}