BSOJ6444题解
神秘做法+1
考虑一个很 simple 的 DP:\(dp[u][c]\) 表示节点 \(u\) 的颜色为 \(c\) 时子树的方案数。
转移是 \(dp[u][x]=\prod_{v\in son_u}{\sum_{x\ne y}dp[v][y]}\)
设 \(g[u]=\sum_{i=1}^{m}dp[u][i]\) 的话,有:
\[dp[u][x]=\prod_{v\in son_u}(g[v]-dp[v][x])
\]
边界条件是叶子结点的 \(dp\) 值均为 \(1\)。
考虑线段树合并。
每次合并结束后用单点修改直接删去单点的值。
然后相当于需要实现:全局取反,全局加,把两个序列做点积。
这三个操作都是简单的。
复杂度 \(O((n+k)\log m)\)。
细节的话
前面两个操作相当于区间加和区间乘。
考虑怎么把对应的位置乘起来。
在线段树合并的时候,有一个节点是空的的时候,说明那一边所有的叶子结点的值一定相同。
把这个值算出来就可以区间乘了。
需要注意不能 pushdown 在合并儿子之前就需要判断。
全局和什么的东西应该很好维护的吧
#include<cstdio>
#include<cctype>
#include<vector>
typedef unsigned ui;
const ui M=1e5+5,mod=998244353;
ui n,m,k,egd,tot,h[M<<1],f[M<<1],rt[M<<1],sum[6*30*M],ls[6*30*M],rs[6*30*M];ui len,stk[6*30*M];
std::vector<ui>c[M<<1];
struct Edge{
ui v,nx;
}e[M<<2];
inline void Add(const ui&u,const ui&v){
e[++egd]=(Edge){v,h[u]};h[u]=egd;
e[++egd]=(Edge){u,h[v]};h[v]=egd;
}
struct func{
ui k,b;
inline func(const ui&k=1,const ui&b=0):k(k),b(b){}
inline ui operator()(const ui&x)const{
return(1ull*k*x+b)%mod;
}
inline func operator()(const func&g)const{
return func(1ull*k*g.k%mod,(1ull*k*g.b+b)%mod);
}
}t[6*30*M];
inline ui nnd(){
const ui u=len?stk[len--]:++tot;ls[u]=rs[u]=sum[u]=0;t[u]=func();return u;
}
inline void del(const ui&u){
stk[++len]=u;
}
inline void push(const ui&u,const func&f,const ui&L,const ui&R){
t[u]=f(t[u]);sum[u]=(1ull*f.k*sum[u]+1ull*f.b*(R-L+1))%mod;
}
inline void pushdown(const ui&u,const ui&L,const ui&R){
if(!ls[u])ls[u]=nnd();if(!rs[u])rs[u]=nnd();
const ui&mid=L+R>>1;push(ls[u],t[u],L,mid);push(rs[u],t[u],mid+1,R);t[u]=func();
}
inline void update(const ui&u,const ui&L,const ui&R){
sum[u]=(1ull*t[u].k*(sum[ls[u]]+sum[rs[u]])+1ull*t[u].b*(R-L+1))%mod;
}
inline void Modify(ui&u,const ui&l,const ui&r,const func&F,const ui&L=1,const ui&R=m){
if(l>R||L>r)return;if(l<=L&&R<=r)return push(u,F,L,R);
const ui&mid=L+R>>1;pushdown(u,L,R);Modify(ls[u],l,r,F,L,mid);Modify(rs[u],l,r,F,mid+1,R);update(u,L,R);
}
inline ui merge(const ui&q,const ui&p,const ui&L=1,const ui&R=m){
if(!q||!p)return del(q|p),q&p;
if(!ls[q]&&!rs[q])return push(p,func(t[q].b),L,R),p;if(!ls[p]&&!rs[p])return push(q,func(t[p].b),L,R),q;
const ui&mid=L+R>>1;pushdown(q,L,R);pushdown(p,L,R);
ls[q]=merge(ls[q],ls[p],L,mid);rs[q]=merge(rs[q],rs[p],mid+1,R);update(q,L,R);del(p);
return q;
}
inline void DFS(const ui&u){
rt[u]=nnd();sum[rt[u]]=m;t[rt[u]]=func(1,1);
for(ui v,E=h[u];E;E=e[E].nx)if((v=e[E].v)^f[u])f[v]=u,DFS(v),rt[u]=merge(rt[u],rt[v]);
for(ui&x:c[u])Modify(rt[u],x,x,func(0,0));if(u^1)Modify(rt[u],1,m,func(mod-1,sum[rt[u]]));
}
inline ui read(){
ui n(0);char s;while(!isdigit(s=getchar()));while(n=n*10+(s&15),isdigit(s=getchar()));return n;
}
signed main(){
n=read();m=read();k=read();
for(ui u,v,i=1;i<n;++i)u=read(),v=read(),Add(u,v);for(ui u,v,i=1;i<=k;++i)u=read(),v=read(),c[u].push_back(v);
DFS(1);printf("%u",sum[rt[1]]);
}