zoukankan      html  css  js  c++  java
  • Luogu P3781 [SDOI2017]切树游戏

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

    [egin{pmatrix}f_v&g_v&1end{pmatrix}egin{pmatrix}lf_u&lf_u&0\0&1&0\lf_u&lf_u+lg_u&1end{pmatrix} ightarrowegin{pmatrix}f_u&g_u&xend{pmatrix} ]

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

    [egin{pmatrix}a&b&0\0&1&0\c&d&1end{pmatrix}egin{pmatrix}a'&b'&0\0&1&0\c'&d'&1end{pmatrix}=egin{pmatrix}aa'&b+ab'&0\0&1&0\a'c+c'&b'c+d+d'&1end{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
    ",tmp[x]);
    	else memset(w[x],0,4*m),w[x][read()]=1,fwt(w[x],0),modify(x);
        }
    }
    
  • 相关阅读:
    Java Tread多线程(2)多线程安全问题
    Android 自己定义ViewGroup 实战篇 -&gt; 实现FlowLayout
    类的继承私有成员问题
    HTTP协议之响应头Date与Age
    《长寿的基因》:尝试挑战主流医学界的观点,态度不严谨,有点像民间科学家。2星。
    《医疗产业大棋局》,4星。有点旧了,依旧是比较难得的有深度的中美两国医疗市场的概括与分析。
    《时间的朋友2016》:吴伯凡写的稿子,比去年李翔写的差。3星。
    《你凭什么做好互联网》。5星。洞察力比较强的从业者的经验集。适合互联网行业各级别各角色阅读。
    《长安十二时辰》。5星。大唐首都反恐24小时。基本是大片剧本。有创意的穿越架空小说。
    读过MBA的CEO更自私?《哈佛商业评论》2016年第12期。4星
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12872501.html
Copyright © 2011-2022 走看看