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

    题目

    二轮毒瘤题啊

    辣鸡洛谷竟然有卡树剖的数据

    还是(loj)可爱

    首先这道题没有带修,设(dp_{i,j})表示以(i)为最高点的连通块有多少个异或和为(j)(g_{i,j}=sum_{kin Tree(i)}dp_{k,j})(kin Tree(i))表示(k)(i)子树内部)

    我们可以直接把每一个权值(fwt)一下,大力合并就好了,合并直接对位相乘,只需要在最后(fwt)回来就好了

    但是我们有了修改,就变成了一道非常恶心的(ddp)

    首先我们(fwt)肯定还是要(fwt)的,我们以下的(dp)都是(fwt)之后的

    考虑我们的方程

    [dp_{i,j}=dp_{i,j}+dp_{i,j} imes dp_{v,j} ]

    [g_{i,j}=dp_{i,j}+g_{v,j} ]

    我们考虑把重儿子和轻儿子分开处理,也就是(ddp)

    (f')表示没有处理重儿子的(dp)数组,(g')表示没有处理重儿子的(g)数组

    我们可以写成这样的矩阵

    [egin{pmatrix} f_{son}\ 1\ g_{son} end{pmatrix} imes egin{pmatrix} f' & f' & 0 \ 0 & 1 & 0 \ f' & f'+g' & 1 end{pmatrix}=egin{pmatrix} f_{u}\ 1\ g_{u} end{pmatrix} ]

    猫老师的博客里提到这个矩阵只有一个地方是有用的,于是我们可以只存(4)个值来表示矩阵,从而大大优化常数

    又因为我们(fwt)之后可以对于每一位单独考虑,于是我们直接来上(128)棵线段树分别维护每一位的值就好了

    有一个问题就是我们需要撤回一个轻儿子的影响

    设没有这个轻儿子的时候为(f'),轻儿子影响为(v)

    则有

    [f=f'+f' imes v ]

    则有

    [f'=frac{f}{1+v} ]

    但是如果(1+v=0),我们没有办法直接除掉这个影响

    所以我们还需要对于每一个点维护出其有多少个轻儿子的会使得(f)变成(0),以及没有这些轻儿子的话(f)的值应该是多少

    这样我们就能解决这个问题了

    但是细节还是有一堆,非常非常难写

    代码

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #define re register
    #define LL long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    const int maxn=30005;
    const int mod=10007;
    const int Inv=5004;
    inline int read() {
        char c=getchar();int x=0;while(c<'0'||x>'9') c=getchar();
        while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    struct E{int v,nxt;}e[maxn<<1];
    struct mat{int a,b,c,d;};
    int n,num,len,m,Q,__;
    int head[maxn],son[maxn],sum[maxn],deep[maxn],fa[maxn],top[maxn],S[128],H[128],inv[mod+5];
    int bot[maxn],dp[maxn][128],g[maxn][128],dfn[maxn],id[maxn],pos[maxn],val[maxn][128];
    int h[maxn][128],tmp[maxn][128],p[maxn][128];
    int l[maxn*3],r[maxn*3];
    inline void add(int x,int y) {
        e[++num].v=y;e[num].nxt=head[x];head[x]=num;
    }
    inline void Fwt(int *f,int o) {
        for(re int i=2;i<=len;i<<=1)
            for(re int ln=i>>1,l=0;l<len;l+=i)
                for(re int x=l;x<l+ln;++x) {
                    int g=f[x],h=f[x+ln];
                    f[x]=(g+h)%mod,f[x+ln]=(g-h+mod)%mod;
                    if(o) f[x]=(f[x]*Inv)%mod,f[x+ln]=(f[x+ln]*Inv)%mod;
                }
    }
    void dfs1(int x) {
        sum[x]=1;
        for(re int i=head[x];i;i=e[i].nxt) {
            if(deep[e[i].v]) continue;
            deep[e[i].v]=deep[x]+1,fa[e[i].v]=x;
            dfs1(e[i].v);sum[x]+=sum[e[i].v];
            if(sum[e[i].v]>=sum[son[x]]) son[x]=e[i].v;
        }
    }
    int dfs2(int x,int topf) {
        top[x]=topf,dfn[x]=++__,id[__]=x;
        if(son[x]) dfs2(son[x],topf);
            else return bot[x]=x;
        for(re int i=head[x];i;i=e[i].nxt)
        if(!top[e[i].v]) bot[e[i].v]=dfs2(e[i].v,e[i].v);
        return bot[x]=bot[son[x]];
    }
    inline mat operator*(mat a,mat b) {
        mat c;
        c.a=a.a*b.a%mod;
        c.b=(a.b+a.a*b.b%mod)%mod;
        c.c=(b.c+b.a*a.c%mod)%mod;
        c.d=(b.b*a.c%mod+a.d+b.d)%mod;
        return c;
    }
    struct Segment_Tree {
        mat d[maxn*3];
        inline void pushup(int i) {d[i]=d[i<<1]*d[i<<1|1];}
        mat query(int x,int y,int i) {
            if(x<=l[i]&&y>=r[i]) return d[i];
            int mid=l[i]+r[i]>>1;
            if(y<=mid) return query(x,y,i<<1);
            if(x>mid) return query(x,y,i<<1|1);
            return query(x,y,i<<1)*query(x,y,i<<1|1);
        }
        inline void change(int i,mat k) {
        	d[i]=k;i>>=1;
        	while(i) {d[i]=d[i<<1]*d[i<<1|1];i>>=1;}
        }
    }t[128];
    void build(int x,int y,int i) {
        l[i]=x,r[i]=y;
        if(x==y) {
            int k=id[x];pos[k]=i;
            for(re int o=head[k];o;o=e[o].nxt) 
            if(deep[e[o].v]>deep[k]&&son[k]!=e[o].v) 
                for(re int j=0;j<len;j++) {
                	dp[k][j]=(dp[k][j]+dp[k][j]*dp[e[o].v][j]%mod)%mod,
                    g[k][j]=(g[k][j]+g[e[o].v][j])%mod,
                    val[k][j]=(val[k][j]*(dp[e[o].v][j]+1))%mod;
                    if((dp[e[o].v][j]+1)%mod!=0) h[k][j]=(h[k][j]*(dp[e[o].v][j]+1))%mod;
                    	else tmp[k][j]++;
                }
            for(re int j=0;j<len;j++)
                t[j].d[i].a=t[j].d[i].b=t[j].d[i].c=dp[k][j],
                t[j].d[i].d=(g[k][j]+dp[k][j])%mod;
            if(son[k]) {
                for(re int j=0;j<len;j++)
                    dp[k][j]=(dp[k][j]+dp[k][j]*dp[son[k]][j]%mod)%mod,
                    g[k][j]=(g[k][j]+g[son[k]][j])%mod;
            }
            for(re int j=0;j<len;j++) g[k][j]=(g[k][j]+dp[k][j])%mod;
            return;
        }
        int mid=x+y>>1;
        build(mid+1,y,i<<1|1),build(x,mid,i<<1);
        for(re int j=0;j<len;j++) t[j].pushup(i);
    }
    signed main() {
        n=read(),len=read();
        for(re int x,i=1;i<=n;i++) {
            x=read();dp[i][x]++;Fwt(dp[i],0);
            for(re int j=0;j<len;j++) h[i][j]=val[i][j]=1,p[i][j]=dp[i][j];
        }
        inv[1]=1;
        for(re int i=2;i<mod;i++) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
        for(re int x,y,i=1;i<n;i++) 
            x=read(),y=read(),add(x,y),add(y,x);
        deep[1]=1;dfs1(1);bot[1]=dfs2(1,1);
        build(1,n,1);char op[10];int x,v,X;
        Q=read();
        while(Q--) {
            scanf("%s",op);
            if(op[0]=='Q') {
                for(re int i=0;i<len;i++) {
                    mat G=t[i].query(1,dfn[bot[1]],1);
                    S[i]=G.d;
                }
                Fwt(S,1);
                x=read();printf("%d
    ",S[x]);
            }else {
            	X=read(),v=read();
            	memset(H,0,sizeof(H));
            	H[v]++;Fwt(H,0);
            	for(re int i=0;i<len;i++) {
            		x=X;if(H[i]==p[x][i]) continue;
            		mat pre=t[i].query(dfn[top[x]],dfn[bot[x]],1);
            		mat now=t[i].d[pos[x]];
            		now.a=H[i]*val[x][i]%mod;
            		now.d=(now.d-now.b+now.a+mod)%mod;
            		now.b=now.c=now.a;
            		t[i].change(pos[x],now);
            		if(top[x]==1) continue;
            		mat G=t[i].query(dfn[top[x]],dfn[bot[x]],1);
            		x=fa[top[x]];
            		while(1) {
            			now=t[i].d[pos[x]];
            			if(inv[pre.b+1]) {
            				now.a=now.a*inv[pre.b+1]%mod;
            				val[x][i]=(val[x][i]*inv[pre.b+1])%mod;
            				h[x][i]=(h[x][i]*inv[pre.b+1])%mod;
                        }
                        else {
                            tmp[x][i]--;
                            if(!tmp[x][i]) 
                                val[x][i]=h[x][i],now.a=(h[x][i]*p[x][i])%mod;
                        }
            			now.a=(now.a+now.a*G.b%mod)%mod;
            			now.d=(now.d-now.b+now.a+mod)%mod;
            			now.d=(now.d-pre.d+G.d+mod)%mod;
            			now.b=now.c=now.a;
            			val[x][i]=(val[x][i]*(G.b+1))%mod;
            			if((G.b+1)%mod==0) tmp[x][i]++;
            				else h[x][i]=(h[x][i]*(G.b+1))%mod;
            			pre=t[i].query(dfn[top[x]],dfn[bot[x]],1);
            			t[i].change(pos[x],now);
            			if(top[x]==1) break;
            			G=t[i].query(dfn[top[x]],dfn[bot[x]],1);
            			x=fa[top[x]];
                    }
                }
                for(re int i=0;i<len;i++) p[X][i]=H[i];
            }
        }
        return 0;
    }
    

    UPD

    (loj)上发现了洛谷上卡树剖的数据的生成器,发现这个数据会反复操作同一个点

    这不就好办了吗,我们开一个栈把修改存下来,每次遇到询问就弹栈,对于一个点只在其第一次出栈时修改

    之后发现有一些取模没有必要,去掉之后就能卡过洛谷数据啦

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #define re register
    #define LL long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    const int maxn=30005;
    const int mod=10007;
    const int Inv=5004;
    inline int read() {
        char c=getchar();int x=0;while(c<'0'||x>'9') c=getchar();
        while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    struct E{int v,nxt;}e[maxn<<1];
    struct mat{int a,b,c,d;};
    int n,num,len,m,Q,__;
    int head[maxn],son[maxn],sum[maxn],deep[maxn],fa[maxn],top[maxn],S[128],H[128],inv[mod+5];
    int bot[maxn],dp[maxn][128],g[maxn][128],dfn[maxn],id[maxn],pos[maxn],val[maxn][128];
    int h[maxn][128],tmp[maxn][128],p[maxn][128];
    int l[maxn*3],r[maxn*3],a[maxn],b[maxn],Top,vis[maxn];
    inline void add(int x,int y) {
        e[++num].v=y;e[num].nxt=head[x];head[x]=num;
    }
    inline void Fwt(int *f,int o) {
        for(re int i=2;i<=len;i<<=1)
            for(re int ln=i>>1,l=0;l<len;l+=i)
                for(re int x=l;x<l+ln;++x) {
                    int g=f[x],h=f[x+ln];
                    f[x]=(g+h)%mod,f[x+ln]=(g-h+mod)%mod;
                    if(o) f[x]=(f[x]*Inv)%mod,f[x+ln]=(f[x+ln]*Inv)%mod;
                }
    }
    void dfs1(int x) {
        sum[x]=1;
        for(re int i=head[x];i;i=e[i].nxt) {
            if(deep[e[i].v]) continue;
            deep[e[i].v]=deep[x]+1,fa[e[i].v]=x;
            dfs1(e[i].v);sum[x]+=sum[e[i].v];
            if(sum[e[i].v]>sum[son[x]]) son[x]=e[i].v;
        }
    }
    int dfs2(int x,int topf) {
        top[x]=topf,dfn[x]=++__,id[__]=x;
        if(son[x]) dfs2(son[x],topf);
            else return bot[x]=x;
        for(re int i=head[x];i;i=e[i].nxt)
        if(!top[e[i].v]) bot[e[i].v]=dfs2(e[i].v,e[i].v);
        return bot[x]=bot[son[x]];
    }
    inline mat operator*(mat a,mat b) {
        mat c;
        c.a=a.a*b.a%mod;
        c.b=(a.b+a.a*b.b)%mod;
        c.c=(b.c+b.a*a.c)%mod;
        c.d=(b.b*a.c%mod+a.d+b.d)%mod;
        return c;
    }
    struct Segment_Tree {
        mat d[maxn*3];
        inline void pushup(int i) {d[i]=d[i<<1]*d[i<<1|1];}
        mat query(const int x,const int y,re int i) {
            if(x<=l[i]&&y>=r[i]) return d[i];
            int mid=l[i]+r[i]>>1;
            if(y<=mid) return query(x,y,i<<1);
            if(x>mid) return query(x,y,i<<1|1);
            return query(x,y,i<<1)*query(x,y,i<<1|1);
        }
        inline void change(re int i,mat k) {
        	d[i]=k;i>>=1;
        	while(i) {pushup(i);i>>=1;}
        }
    }t[128];
    void build(int x,int y,int i) {
        l[i]=x,r[i]=y;
        if(x==y) {
            int k=id[x];pos[k]=i;
            for(re int o=head[k];o;o=e[o].nxt) 
            if(deep[e[o].v]>deep[k]&&son[k]!=e[o].v) 
                for(re int j=0;j<len;j++) {
                	dp[k][j]=(dp[k][j]+dp[k][j]*dp[e[o].v][j])%mod,
                    g[k][j]=(g[k][j]+g[e[o].v][j])%mod,
                    val[k][j]=(val[k][j]*(dp[e[o].v][j]+1))%mod;
                    if((dp[e[o].v][j]+1)%mod!=0) h[k][j]=(h[k][j]*(dp[e[o].v][j]+1))%mod;
                    	else tmp[k][j]++;
                }
            for(re int j=0;j<len;j++)
                t[j].d[i].a=t[j].d[i].b=t[j].d[i].c=dp[k][j],
                t[j].d[i].d=(g[k][j]+dp[k][j])%mod;
            if(son[k]) {
                for(re int j=0;j<len;j++)
                    dp[k][j]=(dp[k][j]+dp[k][j]*dp[son[k]][j])%mod,
                    g[k][j]=(g[k][j]+g[son[k]][j])%mod;
            }
            for(re int j=0;j<len;j++) g[k][j]=(g[k][j]+dp[k][j])%mod;
            return;
        }
        int mid=x+y>>1;
        build(mid+1,y,i<<1|1),build(x,mid,i<<1);
        for(re int j=0;j<len;j++) t[j].pushup(i);
    }
    inline void modify(int X,int v) {
        memset(H,0,sizeof(H));
        H[v]++;Fwt(H,0);int x;
        for(re int i=0;i<len;i++) {
            x=X;if(H[i]==p[x][i]) continue;
            mat pre=t[i].query(dfn[top[x]],dfn[bot[x]],1);
            mat now=t[i].d[pos[x]];
            now.a=H[i]*val[x][i]%mod;
            now.d=(now.d-now.b+now.a+mod)%mod;
            now.b=now.c=now.a;
            t[i].change(pos[x],now);
            if(top[x]==1) continue;
            mat G=t[i].query(dfn[top[x]],dfn[bot[x]],1);
            x=fa[top[x]];
            while(1) {
            	now=t[i].d[pos[x]];
            	if(inv[pre.b+1]) {
            		now.a=now.a*inv[pre.b+1]%mod;
            		val[x][i]=(val[x][i]*inv[pre.b+1])%mod;
            		h[x][i]=(h[x][i]*inv[pre.b+1])%mod;
                }
                else {
                    tmp[x][i]--;
                    if(!tmp[x][i]) 
                            val[x][i]=h[x][i],now.a=(h[x][i]*p[x][i])%mod;
                }
            	now.a=(now.a+now.a*G.b)%mod;
            	now.d=(now.d-now.b+now.a+mod)%mod;
            	now.d=(now.d-pre.d+G.d+mod)%mod;
            	now.b=now.c=now.a;
            	val[x][i]=(val[x][i]*(G.b+1))%mod;
            	if((G.b+1)%mod==0) tmp[x][i]++;
            		else h[x][i]=(h[x][i]*(G.b+1))%mod;
            	pre=t[i].query(dfn[top[x]],dfn[bot[x]],1);
            	t[i].change(pos[x],now);
            	if(top[x]==1) break;
            	G=t[i].query(dfn[top[x]],dfn[bot[x]],1);
            	x=fa[top[x]];
            }
        }
        for(re int i=0;i<len;i++) p[X][i]=H[i];
    }
    signed main() {
        n=read(),len=read();
        for(re int x,i=1;i<=n;i++) {
            x=read();dp[i][x]++;Fwt(dp[i],0);
            for(re int j=0;j<len;j++) h[i][j]=val[i][j]=1,p[i][j]=dp[i][j];
        }
        inv[1]=1;
        for(re int i=2;i<mod;i++) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
        for(re int x,y,i=1;i<n;i++) 
            x=read(),y=read(),add(x,y),add(y,x);
        deep[1]=1;dfs1(1);bot[1]=dfs2(1,1);
        build(1,n,1);char op[10];int x,v,X;
        Q=read();
        while(Q--) {
            scanf("%s",op);
            if(op[0]=='Q') {
            	int mid=Top;
            	while(Top) {
            		if(!vis[a[Top]]) modify(a[Top],b[Top]);
            		vis[a[Top]]=1;
                    Top--; 
                }
                for(re int i=1;i<=mid;i++) vis[a[i]]=0;
                for(re int i=0;i<len;i++) {
                    mat G=t[i].query(1,dfn[bot[1]],1);
                    S[i]=G.d;
                }
                Fwt(S,1);
                x=read();printf("%d
    ",S[x]);
            }else {
            	x=read(),v=read(),a[++Top]=x,b[Top]=v;
        	}
        }
        return 0;
    }
    
  • 相关阅读:
    Oracle DB管理内存
    DISPLAY变量和xhost(原创)
    CentOS7下swap分区创建(添加),删除以及相关配置
    如何在linux下开启FTP服务
    linux系统下如何挂载NTFS移动硬盘
    Oracle DB 使用RMAN恢复目录
    Oracle数据库联机重定义讲解及错误处理
    linux常用命令
    iptables常用命令
    python打印详细的异常信息
  • 原文地址:https://www.cnblogs.com/asuldb/p/10698273.html
Copyright © 2011-2022 走看看