Luogu P3781 [SDOI2017]切树游戏

Link
\(f_{u,i}\)表示根为\(u\)的异或和为\(i\)的连通块的个数。
那么我们有如下转移:\(f_{u,i}f_{v,j}\rightarrow f_{u,i\operatorname{xor}j}(v\in son_u)\)
考虑FWT优化,FWT之后转移就变成了\(f_{u,i}(f_{v,i}+1)\rightarrow f_{u,i}\)
\(g_{u,i}=\sum\limits_{v\in subtree_u}f_{v,i}\),那么\(\operatorname{IDFT}(g_1)\)就是答案序列。
考虑ddp优化,设\(lf_{u,i}=\prod\limits_{v\in lightson_u}(1+f_{v,i}),lg_{u,i}=\sum\limits_{v\in lightson_u}g_{v,i}lf_{u,i}\)
那么重链上的转移就是

\[\begin{pmatrix}f_v&g_v&1\end{pmatrix}\begin{pmatrix}lf_u&lf_u&0\\0&1&0\\lf_u&lf_u+lg_u&1\end{pmatrix}\rightarrow\begin{pmatrix}f_u&g_u&x\end{pmatrix} \]

在维护\(LF_u(x)\)的时候可能会会出现除以一个模意义下为\(0\)的数的情况,用\(r\times0^t\)表示数即可。
转移矩阵的乘法可以进行优化:

\[\begin{pmatrix}a&b&0\\0&1&0\\c&d&1\end{pmatrix}\begin{pmatrix}a'&b'&0\\0&1&0\\c'&d'&1\end{pmatrix}=\begin{pmatrix}aa'&b+ab'&0\\0&1&0\\a'c+c'&b'c+d+d'&1\end{pmatrix} \]

#include<cctype>
#include<cstdio>
#include<vector>
#include<cstring>
#include<utility>
using pi=std::pair<int,int>;
const int N=30007,M=129,P=10007;
int n,m,q,w[N][M],son[N],fa[N],ch[N],top[N],dfn[N],id[N],ans[M],inv[P];
pi h[N][M];char opt[15];std::vector<int>e[N];
void inc(int&a,int b){a+=b-P,a+=a>>31&P;}
void dec(int&a,int b){a-=b,a+=a>>31&P;}
void mul(int&a,int b){a=1ll*a*b%P;}
int read(){int x=0,c=getchar();while(isspace(c))c=getchar();while(isdigit(c))(x*=10)+=c&15,c=getchar();return x;}
void fwt(int*a,int f)
{
    for(int i=1;i<m;i*=2) for(int j=0;j<m;j+=i+i) for(int k=0,x;k<i;++k) x=a[i|j|k],dec(a[i|j|k]=a[j|k],x),inc(a[j|k],x);
    if(!~f) for(int i=0,x=inv[m];i<m;++i) mul(a[i],x);
}
void dfs1(int u)
{
    static int size[N];size[u]=1;
    for(int v:e[u]) if(v^fa[u]) if(fa[v]=u,dfs1(v),size[u]+=size[v],size[v]>size[son[u]]) son[u]=v;
}
void dfs2(int u,int tp)
{
    static int tim,f[N][M];id[dfn[u]=++tim]=u,top[u]=tp,ch[u]=u;
    if(son[u]) dfs2(son[u],tp),ch[u]=ch[son[u]];
    for(int i=0;i<m;++i) h[u][i].first=1;
    for(int v:e[u])
	if(v^fa[u]&&v^son[u])
	{
	    dfs2(v,v);
	    for(int i=0;i<m;++i) if(f[v][i]==P-1) ++h[u][i].second; else mul(h[u][i].first,f[v][i]+1);
	}
    for(int i=0;i<m;++i) inc(ans[i],f[u][i]=h[u][i].second? 0:1ll*h[u][i].first*(f[son[u]][i]+1)%P*w[u][i]%P);
}
struct node
{
    int s[M],l[M],r[M],p[M];
    node(){memset(s,0,sizeof s),memset(l,0,sizeof l),memset(r,0,sizeof r),memset(p,0,sizeof p);}
    void init(int x){for(int i=0;i<m;++i)s[i]=l[i]=r[i]=p[i]=h[x][i].second? 0:1ll*h[x][i].first*w[x][i]%P;}
}t[4*N];
node operator+(node a,node b)
{
    node c;
    for(int i=0;i<m;++i) c.s[i]=(a.s[i]+b.s[i]+1ll*a.r[i]*b.l[i])%P,c.l[i]=(a.l[i]+a.p[i]*b.l[i])%P,c.r[i]=(b.r[i]+b.p[i]*a.r[i])%P,c.p[i]=a.p[i]*b.p[i]%P;
    return c;
}
#define ls p<<1
#define rs p<<1|1
#define mid ((l+r)/2)
void build(int p,int l,int r)
{
    if(l==r) return t[p].init(id[l]);
    build(ls,l,mid),build(rs,mid+1,r),t[p]=t[ls]+t[rs];
}
void update(int p,int l,int r,int x)
{
    if(l==r) return t[p].init(id[x]);
    x<=mid? update(ls,l,mid,x):update(rs,mid+1,r,x),t[p]=t[ls]+t[rs];
}
node query(int p,int l,int r,int L,int R)
{
    if(L<=l&&r<=R) return t[p];
    if(R<=mid) return query(ls,l,mid,L,R);
    if(L>mid) return query(rs,mid+1,r,L,R);
    return query(ls,l,mid,L,R)+query(rs,mid+1,r,L,R);
}
#undef ls
#undef rs
#undef mid
void cut(int u,int f)
{
    node tmp=query(1,1,n,dfn[u],dfn[ch[u]]);
    for(int i=0;i<m;++i) (~f? inc:dec)(ans[i],tmp.s[i]);
    if(!fa[u]) return ;
    for(int i=0,val;i<m;++i) if((val=tmp.l[i]+1)==P) h[fa[u]][i].second+=f; else mul(h[fa[u]][i].first,~f? val:inv[val]);
}
void modify(int u){for(;u;u=fa[top[u]]) cut(top[u],-1),update(1,1,n,dfn[u]),cut(top[u],1);}
int main()
{
    n=read(),m=read(),inv[0]=inv[1]=1;static int tmp[M];
    for(int i=2;i<P;++i) inv[i]=(P-P/i)*inv[P%i]%P;
    for(int i=1;i<=n;++i) w[i][read()]=1,fwt(w[i],1);
    for(int i=1,u,v;i<n;++i) u=read(),v=read(),e[u].push_back(v),e[v].push_back(u);
    dfs1(1),dfs2(1,1),build(1,1,n);
    for(int q=read(),x;q;--q)
    {
	scanf("%s",opt),x=read();
	if(opt[0]=='Q') memcpy(tmp,ans,4*m),fwt(tmp,-1),printf("%d\n",tmp[x]);
	else memset(w[x],0,4*m),w[x][read()]=1,fwt(w[x],0),modify(x);
    }
}
posted @ 2020-05-11 21:57  Shiina_Mashiro  阅读(138)  评论(0编辑  收藏  举报