题目

二轮毒瘤题啊

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

还是\(loj\)可爱

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

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

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

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

考虑我们的方程

\[dp_{i,j}=dp_{i,j}+dp_{i,j}\times dp_{v,j}
\]

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

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

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

我们可以写成这样的矩阵

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

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

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

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

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

则有

\[f=f'+f'\times 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\n",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\n",S[x]);
}else {
x=read(),v=read(),a[++Top]=x,b[Top]=v;
}
}
return 0;
}

[SDOI2017]切树游戏的更多相关文章

  1. 【BZOJ4911】[SDOI2017]切树游戏(动态dp,FWT)

    [BZOJ4911][SDOI2017]切树游戏(动态dp,FWT) 题面 BZOJ 洛谷 LOJ 题解 首先考虑如何暴力\(dp\),设\(f[i][S]\)表示当前以\(i\)节点为根节点,联通子 ...

  2. BZOJ4911: [Sdoi2017]切树游戏

    BZOJ 4911 切树游戏 重构了三次.jpg 每次都把这个问题想简单了.jpg 果然我还是太菜了.jpg 这种题的题解可以一眼秒掉了,FWT+动态DP简直是裸的一批... 那么接下来,考虑如何维护 ...

  3. LG3781 [SDOI2017]切树游戏

    题意 题目描述 小Q是一个热爱学习的人,他经常去维基百科学习计算机科学. 就在刚才,小Q认真地学习了一系列位运算符,其中按位异或的运算符\(\oplus\)对他影响很大.按位异或的运算符是双目运算符. ...

  4. LOJ2269 [SDOI2017] 切树游戏 【FWT】【动态DP】【树链剖分】【线段树】

    题目分析: 好题.本来是一道好的非套路题,但是不凑巧的是当年有一位国家集训队员正好介绍了这个算法. 首先考虑静态的情况.这个的DP方程非常容易写出来. 接着可以注意到对于异或结果的计数可以看成一个FW ...

  5. bzoj 4911: [Sdoi2017]切树游戏

    考虑维护原树的lct,在上面dp,由于dp方程特殊,均为异或卷积或加法,计算中可以只使用fwt后的序列 v[w]表示联通子树的最浅点为w,且不选w的splay子树中的点 l[w]表示联通子树的最浅点在 ...

  6. 洛谷 P3781 - [SDOI2017]切树游戏(动态 DP+FWT)

    洛谷题面传送门 SDOI 2017 R2 D1 T3,nb tea %%% 讲个笑话,最近我在学动态 dp,wjz 在学 FWT,而我们刚好在同一天做到了这道题,而这道题刚好又是 FWT+动态 dp ...

  7. 【LOJ】#2269. 「SDOI2017」切树游戏

    题解 把所有的数组一开始就FWT好然后再IFWT回去可以减小常数 从13s跑到0.7s-- 可以参照immortalCO的论文,感受一下毒瘤的动态动态DP 就是用数据结构维护线性递推的矩阵的乘积 由于 ...

  8. loj#2269. 「SDOI2017」切树游戏

    还是loj的机子快啊... 普通的DP不难想到,设F[i][zt]为带上根玩出zt的方案数,G[i][zt]为子树中的方案数,后面是可以用FWT优化的 主要是复习了下动态DP #include< ...

  9. LOJ2269. 「SDOI2017」切树游戏 [FWT,动态DP]

    LOJ 思路 显然是要DP的.设\(dp_{u,i}\)表示\(u\)子树内一个包含\(u\)的连通块异或出\(i\)的方案数,发现转移可以用FWT优化,写成生成函数就是这样的: \[ dp_{u}= ...

随机推荐

  1. Java注解(三)

    上一篇了解了自定义注解的使用,不过里面的例子没有多大使用价值,这一回来个有用点的Demo. 目标:将实体bean保存到数据库 先来定义一个实体注解 import java.lang.annotatio ...

  2. mysql根据经纬度求两地距离

    #1.两点距离(1.4142135623730951) ,),point(,)); select st_distance(point (120.10591, 30.30163),point(120.1 ...

  3. PCA vs Linear Regression 可视化理解

    https://shankarmsy.github.io/posts/pca-vs-lr.html https://shapeofdata.wordpress.com/2013/04/09/princ ...

  4. POJ3278(KB1-C 简单搜索)

    Catch That Cow Description Farmer John has been informed of the location of a fugitive cow and wants ...

  5. 正能量:You Are the Best

    Success comes from knowing that you did your best to become the best that you are capable of becomin ...

  6. IOT安全

    相关资源 IOT 漏洞 top 10 https://xz.aliyun.com/t/2278 https://www.owasp.org/images/8/8e/Infographic-v1.jpg ...

  7. Django 配置mysql

    1.创建数据库 create database django_lianxi charset=utf8; 2.django项目文件夹的setting.py设置 Django项目默认 sqlite3 数据 ...

  8. css.map作用

    看一段sass代码: 嵌套书写的结构在sass中经常会被用到. 编译之后的样式是这样的: 在开发工具上我们看到的是编译后的文件,而非编译前的源文件. 这个时候就产生一个问题了.在生产环境中,我希望看到 ...

  9. commonjs详解

    marked here a well written artical http://javascript.ruanyifeng.com/nodejs/module.html

  10. -webkit-min-device-pixel-ratio: 2是什么意思?

    DPI(DPR) stands for Dots Per Inch which technically means printer dots per inch. 这个参数实际上量化了屏幕的物理分辨率和 ...