目前暂无修正。
前置知识:扩展域并查集、树形 DP、离线二维数点(不必要?)。
水个题解,写一个常数大、码量大、难写、简单问题复杂化的思路。时间复杂度 \(O(n\log n+(n+m)\alpha(n))\)。
假定树是以 \(1\) 为根的有根树,我们让边权为 \(0\) 表示向下,\(1\) 表示向上。首先设 \(f_{u,0/1}\) 表示以 \(u\) 为根的子树中,\(u\) 与其父亲 \(fa\) 连边权值为 \(0/1\) 的方案数。
考虑转移,发现在输入节点对 \((a_i,b_i)\) 时可以把它挂到 \(lc=\text{LCA}(a_i,b_i)\) 上处理,若 \(lc\neq a_i\land lc\neq b_i\),我们找到 \(lc\) 包含 \(a_i,b_i\) 的子树树根分别记为 \(A,B\),则当 DP 处理 \(lc\) 时 \(f_{A,0}\) 只能和 \(f_{B,1}\) 结合,\(f_{A,1}\) 只能和 \(f_{B,0}\) 结合。
同理,我们发现 \(a_i\to A,b_i\to B\) 这两条链上边权必须都相等。于是我们考虑能否在处理 \(lc\) 时找到在与 \(lc\) 其他子树的点匹配后仍有剩余点的子树,这个东西我不会求所以糊了个离线二维数点上去,通过 DFS 序找出 \(v\) 与 \(u\) 匹配后消掉了多少个点 \(cut_v\),然后再用树上差分算出 \(v\) 子树内原来剩余未匹配点数 \(cnt_v\),如果 \(cnt_v-cut_v>0\) 就存在剩余(具体实现:\((a_i,b_i),(b_i,a_i)\) 单点加,\(cut_v\) 求 \(x\in[dfn_v,dfn_v+siz_v-1]\land y\in[dfn_u,dfn_u+siz_u-1]\text{ 的 }(x,y)\text{ 数量}-x\in[dfn_v,dfn_v+siz_v-1]\land y\in[dfn_v,dfn_v+siz_v-1]\text{ 的 }(x,y)\text{ 数量}\))。
找到的这些 \(v\) 子树一定有 \(f_{v,0}\) 转移到 \(f_{u,0}\),\(f_{v,1}\) 转移到 \(f_{u,1}\)。不妨对每个点设一个状态 \((v,0)\) 代表 \(f_{v,0}\),\((v,1)\) 代表 \(f_{v,1}\),并查集维护连通性,在一个连通块内才能相互结合。只需一开始找到挂在 \(lc\) 上的 \(A,B\) 并连边 \((A,0)-(B,1),(A,1)-(B,0)\)。对于仍有剩余点的子树 \(v_i\) 把所有 \((v_i,0)\) 串起来,\((v_i,1)\) 串起来即可。每个连通块 \(a_X\) 的贡献就是其点权乘积。\(f_{u,0/1}\) 和 \(f_{v_i,0/1}\) 分别强制捆绑,然后每次找到一对连通块 \(X,Y\)(因为连边是对称的),其对 \(f_{u,0/1}\) 都有贡献 \(a_X+a_Y\)。直接转移即可。
最后答案是 \(f_{1,0}\) 或 \(f_{1,1}\),代码不建议参考,仅提供一个构式的思路。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL MOD=1e9+7;
const int N=3e5+5;
int n,m,son[N],dep[N],dfn[N],tms;
int top[N],fat[N],siz[N];
int unc[N],fa[N*2],cut[N];
LL f[N][2];
struct BIT{int av[N];inline int lowbit(int x){return x&-x;}void add(int p,int x){for(int i=p;i<=n;i+=lowbit(i))av[i]+=x;}int que(int p){int res=0;for(int i=p;i;i-=lowbit(i)){res+=av[i];}return res;}
}T;
struct Q{int l,r,id;};
vector<int>G[N],Add[N];
vector<Q>q[N];
inline int fr(int x){return fa[x]==x?x:fa[x]=fr(fa[x]);}
void ins(int x,int y){int frx=fr(x),fry=fr(y);if(frx==fry)return ;fa[frx]=fry;
}
void dfs0(int u,int fa){dep[u]=dep[fa]+1;siz[u]=1;fat[u]=fa;for(int v:G[u]){if(v==fa)continue;dfs0(v,u);siz[u]+=siz[v];if(siz[v]>siz[son[u]])son[u]=v;}
}
void dfs1(int u){dfn[u]=++tms;int fa=fat[u];if(son[fa]==u)top[u]=top[fa];else top[u]=u;if(son[u])dfs1(son[u]);for(int v:G[u]){if(v==fa||v==son[u])continue;dfs1(v);}
}
int LCA(int x,int y){while(top[x]!=top[y]){if(dep[top[x]]<dep[top[y]])swap(x,y);x=fat[top[x]];}if(dep[x]>dep[y])swap(x,y);return x;
}
int jump(int x,int y){int last=0;while(top[x]!=top[y]){if(dep[top[x]]<dep[top[y]])swap(x,y);last=top[x],x=fat[top[x]];}if(dep[x]>dep[y])swap(x,y);if(x==y)return last;return son[x];
}
bool vis[N*2];
void dfs(int u){int fa=fat[u],ex=0;for(int v:G[u]){if(v==fa)continue;dfs(v);unc[u]+=unc[v];if(unc[v]-cut[v]>0)ex=v;}if(!son[u])f[u][0]=1,f[u][1]=1;else {bool tf=1;for(int v:G[u]){if(v==fa)continue;if(fr(v)==fr(v+n)){tf=0;break;}if(unc[v]-cut[v]>0)ins(v,ex),ins(v+n,ex+n);}if(!tf){f[u][0]=f[u][1]=0;return ;}for(int v:G[u]){if(v==fa)continue;if(fr(v)>n)f[fr(v)-n][1]=f[fr(v)-n][1]*f[v][0]%MOD;else if(fr(v)!=v)f[fr(v)][0]=f[fr(v)][0]*f[v][0]%MOD;if(fr(v+n)<=n)f[fr(v+n)][0]=f[fr(v+n)][0]*f[v][1]%MOD;else if(fr(v+n)!=v+n)f[fr(v+n)-n][1]=f[fr(v+n)-n][1]*f[v][1]%MOD;}int frex=0,frexn=0;if(ex){frex=fr(ex),frexn=fr(ex+n);vis[frex]=vis[frexn]=1;f[u][0]=(frex<=n?f[frex][0]:f[frex-n][1]);f[u][1]=(frexn<=n?f[frexn][0]:f[frexn-n][1]);}else f[u][0]=f[u][1]=1;for(int v:G[u]){if(v==fa)continue;assert(!(vis[fr(v)]^vis[fr(v+n)]));if(vis[fr(v)]||vis[fr(v+n)])continue;vis[fr(v)]=vis[fr(v+n)]=1;int a=fr(v),b=fr(v+n);bool ga=0,gb=0;if(a>n)a-=n,ga=1;if(b>n)b-=n,gb=1;f[u][0]=f[u][0]*(f[a][ga]+f[b][gb])%MOD;f[u][1]=f[u][1]*(f[a][ga]+f[b][gb])%MOD;}}
}
int main(){//freopen("dispatch.in","r",stdin);//freopen("dispatch.out","w",stdout);scanf("%d%d",&n,&m);for(int i=1;i<=2*n;i++)fa[i]=i;for(int i=1;i<n;i++){int u,v;scanf("%d%d",&u,&v);G[u].emplace_back(v);G[v].emplace_back(u); }dfs0(1,0);dfs1(1);for(int i=2;i<=n;i++){int v=i,u=fat[v];q[dfn[v]-1].emplace_back(Q{dfn[u],dfn[u]+siz[u]-1,-v});q[dfn[v]+siz[v]-1].emplace_back(Q{dfn[u],dfn[u]+siz[u]-1,v});q[dfn[v]-1].emplace_back(Q{dfn[v],dfn[v]+siz[v]-1,v});q[dfn[v]+siz[v]-1].emplace_back(Q{dfn[v],dfn[v]+siz[v]-1,-v});}for(int i=1;i<=m;i++){int a,b;scanf("%d%d",&a,&b);Add[dfn[a]].emplace_back(dfn[b]);Add[dfn[b]].emplace_back(dfn[a]);int lc=LCA(a,b);unc[a]++;unc[b]++;unc[lc]-=2;if(lc!=a&&lc!=b){a=jump(a,lc);b=jump(b,lc);ins(a,b+n);ins(b,a+n);}}for(int i=1;i<=n;i++){for(int v:Add[i])T.add(v,1);for(Q v:q[i]){if(v.id>0)cut[v.id]+=T.que(v.r)-T.que(v.l-1);else cut[-v.id]-=T.que(v.r)-T.que(v.l-1);}}dfs(1);printf("%lld",f[1][0]);return 0;
}