正题
题目链接:https://www.luogu.com.cn/problem/P6773
题目大意
nnn个点的一棵树,边权可以是000或111。mmm个条件(x,y)(x,y)(x,y)表示要求x,yx,yx,y之间要有边权值为111(保证xxx是yyy的祖先),求方案数。
解题思路
考虑容斥,首先我们把没有用的条件去掉(就是被其他条件包含的),如果有kkk条路径上没有111那么容斥系数为∣−1∣k|-1|^k∣−1∣k。
设fi,jf_{i,j}fi,j表示点iii的子树中,要再往上到深度为jjj的节点都不能是111时的答案,那么有转移方程fx,min{j,k}=fx,j∗fy,kf_{x,min\{j,k\}}=f_{x,j}*f_{y,k}fx,min{j,k}=fx,j∗fy,k
这是一个min−maxmin-maxmin−max卷积的形式,用线段树合并维护即可。
时间复杂度O(nlogn)O(n\log n)O(nlogn)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=5e5+10,XJQ=998244353;
struct node{ll to,next;
}a[N*2];
ll n,m,tot,ls[N],dep[N],rt[N],up[N];
struct Seq_Tree{ll cnt,w[N<<6],ls[N<<6],rs[N<<6],lazy[N<<6];void Downdata(ll x){if(lazy[x]==1)return;w[ls[x]]=w[ls[x]]*lazy[x]%XJQ;w[rs[x]]=w[rs[x]]*lazy[x]%XJQ;lazy[ls[x]]=lazy[ls[x]]*lazy[x]%XJQ;lazy[rs[x]]=lazy[rs[x]]*lazy[x]%XJQ;lazy[x]=1;return;}void Insert(ll &x,ll L,ll R,ll pos,ll val){if(!x)x=++cnt,lazy[x]=1;if(L==R){w[x]+=val;return;}ll mid=(L+R)>>1;Downdata(x);if(pos<=mid)Insert(ls[x],L,mid,pos,val);else Insert(rs[x],mid+1,R,pos,val);w[x]=(w[ls[x]]+w[rs[x]])%XJQ;return;}void Change(ll &x,ll L,ll R,ll l,ll r){if(!x)x=++cnt,lazy[x]=1;if(L==l&&R==r){lazy[x]=lazy[x]*2%XJQ;w[x]=w[x]*2%XJQ;return;}ll mid=(L+R)>>1;Downdata(x);if(r<=mid)Change(ls[x],L,mid,l,r);else if(l>mid)Change(rs[x],mid+1,R,l,r);else Change(ls[x],L,mid,l,mid),Change(rs[x],mid+1,R,mid+1,r);w[x]=(w[ls[x]]+w[rs[x]])%XJQ;return;}ll Merge(ll x,ll y,ll l,ll r,ll w1,ll w2){if(!x||!y){w[x]=w[x]*w2%XJQ;lazy[x]=lazy[x]*w2%XJQ;w[y]=w[y]*w1%XJQ;lazy[y]=lazy[y]*w1%XJQ;return x+y;}if(l==r){w[x]=(w[x]*w[y]+w[x]*w2+w[y]*w1)%XJQ;return x;}ll mid=(l+r)>>1;Downdata(x);Downdata(y);ls[x]=Merge(ls[x],ls[y],l,mid,(w1+w[rs[x]])%XJQ,(w2+w[rs[y]])%XJQ);rs[x]=Merge(rs[x],rs[y],mid+1,r,w1,w2);w[x]=(w[ls[x]]+w[rs[x]])%XJQ;return x; }
}T;
void addl(ll x,ll y){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;return;
}
void dfs(ll x,ll fa){dep[x]=dep[fa]+1;for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(y==fa)continue;dfs(y,x);}return;
}
void solve(ll x,ll fa){if(up[x])T.Insert(rt[x],1,n,up[x],XJQ-1);T.Insert(rt[x],1,n,n,1);for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(y==fa)continue;solve(y,x);T.Change(rt[y],1,n,dep[y],n);rt[x]=T.Merge(rt[x],rt[y],1,n,0,0);}
// printf("%d\n",T.w[rt[x]]);return;
}
int main()
{scanf("%lld",&n);for(ll i=1;i<n;i++){ll x,y;scanf("%lld%lld",&x,&y);addl(x,y);addl(y,x);}dfs(1,0);scanf("%lld",&m);while(m--){ll x,y;scanf("%lld%lld",&x,&y);up[y]=max(up[y],dep[x]);}solve(1,0);printf("%lld",T.w[rt[1]]);return 0;
}