小Q是一个热爱学习的人,他经常去维基百科学习计算机科学。
就在刚才,小Q认真地学习了一系列位运算符,其中按位异或的运算符 ⊕ 对他影响很大。按位异或的运算符是双目运算符。按位异或具有交换律,即 i⊕j=j⊕i 。
他发现,按位异或可以理解成被运算的数字的二进制位对应位如果相同,则结果的该位置为0,否则为1,例如: 1(01)⊕2(10)=3(11) 。
他还发现,按位异或可以理解成参与运算的数字的每个二进制位都进行了不进位的加法,例如: 3(11)⊕3(11)=0(00) 。
现在小Q有一棵 n 个结点的无根树 T ,结点依次编号为 1 到 n ,其中结点 i 的权值为 vi 。
定义一棵树的价值为它所有点的权值的异或和,一棵树 T 的连通子树就是它的一个连通子图,并且这个图也是一棵树。
小Q想要在这棵树上玩切树游戏,他会不断做以下两种操作:
Change x y 将编号为 x 的结点的权值修改为 y 。
Query k 询问有多少棵 T 的非空连通子树,满足其价值恰好为 k 。
小Q非常喜(bu)欢(hui)数学,他希望你能快速回答他的问题,你能写个程序帮帮他吗?
第一行包含两个正整数 n , m ,分别表示结点的个数以及权值的上限。
第二行包含 n 个非负整数 v1,v2,…,vn ,分别表示每个结点一开始的权值。
接下来 n−1 行,每行包含两个正整数 ai,bi ,表示有一条连接 ai 和 bi 的无向树边。
接下来一行包含一个正整数 q ,表示小Q操作的次数。
接下来 q 行每行依次表示每个操作。
输出若干行,每行一个整数,依次回答每个询问。因为答案可能很大,所以请对1000710007取模输出。
4 4
2 0 1 3
1 2
1 3
1 4
12
Query 0
Query 1
Query 2
Query 3
Change 1 0
Change 2 1
Change 3 3
Change 4 1
Query 0
Query 1
Query 2
Query 3
3
3
2
3
2
4
2
3
对于 100% 的数据, 1≤ai,bi,x≤n , 0≤vi,y,k<m ,修改操作不超过 10000 个。
神题一道,学习到了链分治的新姿势~
然而第一次写会感觉特别难写难调…..
于是本蒟蒻调了一上午+一下午
思路:
首先可以列出朴素的dp方程:
令 g[i][j][k] 代表当前在 i 节点,处理到了 j 号儿子 chj ,子树异或和为 k 的方案数。
令 f[i][j] 代表当前在 i 节点,子树异或和为 j 的方案数。
那么:
g[i][1][k]=f[ch(i)1][k]
g[i][j][k]=∑g[i][j−1][l]∗(f[ch(i)j][k∧w]+[k==w])
f[i][j]=g[i][|ch(i)|][j]
可以发现第二行的转移是个异或卷积的形式,那么套个FWT变成 O(128) 转移。
此时,如果是静态查询,很明显一发 dsu on tree 就做完了~
然而这是动态的。
所以考虑使用链分治。
什么是链分治?
首先考虑树链剖分,找出重链。
链分治就是,对每条重链上的信息,单独建一棵线段树来维护,从而达到动态修改的效果。
在链分治时,将会直接用单独的一棵线段树维护一根重链的信息,此时每个节点的权值便是它只考虑所有轻边的情况下的dp值。
然后计算某条重链链顶的贡献时,在线段树向上更新合并区间时互相dp,最后根节点的信息便是这条链链顶的结果了。
然后把这个根节点的贡献传到链顶的父亲所在线段树中属于父亲的叶子结点处,并更新父亲所在重链的线段树,以此类推,直到更新完根节点时就完成了!
对于这道题,需要维护四个tag,其中一个是子树的 f 值之和 h 。
可以发现在进行一次FWT后,令 ei 为 [i==0] 的数组的FWT结果,则更新dp的式子写成生成函数后如下:
fi(e)=evi∏j∈chfj(e)+e0
也就是说,对于每个点,要维护来自轻边的贡献,而这是一个连乘,直接做即可~。
剩下的是合并信息,同样是乘法合并。
于是需要维护区间乘以及每一小段乘积之和(这是 h ),这些就是线段树基本操作了,具体见代码~
考虑到0的逆元问题,需要手写一个可以在模意义下除以0并乘以0的类(就是记录是否被过多的0乘过)。
#include
#include
#include
#include
#include
#include
using namespace std;
#define mid ((l+r)>>1)
typedef long long ll;
const int N=30009;
const int M=N*3;
const int K=309;
const int md=10007;
const int inv2=(md+1)>>1;
int n,k,m,l;
int val[N],ans[K],tmp[K];
int to[N<<1],nxt[N<<1],beg[N],tot;
int fa[N],siz[N],son[N],dep[N];
int top[N],stk[N],stop;
int inv[md+3],e[K][K];
int root[N],pos[N],pool;
int h[M][K],lval[M][K],rval[M][K],sum[M][K],ls[M],rs[M],tfa[M];
vector<int> v[N];
struct int0
{
int a,b;
int0(int _a=0)
{
if(_a)a=_a,b=0;
else a=1,b=1;
}
friend int0 operator * (int0 o,int v)
{
if(!v)o.b++;
else o.a=o.a*v%md;
return o;
}
friend int0 operator / (int0 o,int v)
{
if(!v)o.b--;
else o.a=o.a*inv[v]%md;
return o;
}
inline int get()
{
if(b)return 0;
else return a;
}
}f[N][K];
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0' || '9'if(ch=='-')f=-1;ch=getchar();}
while('0'<=ch && ch<='9')x=x*10+(ch^48),ch=getchar();
return x*f;
}
inline void add(int u,int v)
{
to[++tot]=v;
nxt[tot]=beg[u];
beg[u]=tot;
}
inline int qpow(int a,int b)
{
int ret=1;
while(b)
{
if(b&1)
ret=ret*a%md;
a=a*a%md;
b>>=1;
}
return ret;
}
inline void FWT(int *a,int n,bool f)
{
for(int h=2;h<=n;h<<=1)
for(int j=0;jfor(int k=j;k>1);k++)
{
int x=a[k],y=a[k+(h>>1)];
a[k]=(x+y)%md;
a[k+(h>>1)]=(x-y+md)%md;
if(f)
{
a[k]=a[k]*inv2%md;
a[k+(h>>1)]=a[k+(h>>1)]*inv2%md;
}
}
}
inline void init()
{
for(m=1;m1);k=m;
for(int i=0;i1;
FWT(e[i],k,0);
}
inv[1]=1;
for(int i=2;i2);
for(int i=1;i<=n;i++)
for(int j=0;jinline void dfs(int u)
{
siz[u]=1;son[u]=0;
for(int i=beg[u],v;i;i=nxt[i])
if((v=to[i])!=fa[u])
{
fa[v]=u;
dep[v]=dep[u]+1;
dfs(v);
siz[u]+=siz[v];
if(!son[u] || siz[son[u]]inline void dfs2(int u)
{
v[top[u]].push_back(u);
if(top[u]==u)stk[++stop]=u;
if(son[u])
{
top[son[u]]=top[u];
dfs2(son[u]);
for(int i=beg[u],v;i;i=nxt[i])
if((v=to[i])!=fa[u] && v!=son[u])
dfs2(top[v]=v);
}
}
inline bool cmp(int a,int b)
{
return dep[a]>dep[b];
}
inline void update(int x)
{
for(int i=0;iinline int build(int l,int r,int x)
{
int now=++pool;
if(l==r)
{
for(int i=0;i1]][i].get();
pos[v[x][l-1]]=now;
return now;
}
tfa[ls[now]=build(l,mid,x)]=now;
tfa[rs[now]=build(mid+1,r,x)]=now;
update(now);
return now;
}
inline void change(int u)
{
int x=pos[u],tp=top[u];
if(fa[tp])
for(int i=0;i0][i])%md);
for(int i=0;ifor(int i=0;ifor(x=tfa[x];x;x=tfa[x])
update(x);
if(fa[tp])
for(int i=0;i0][i])%md);
for(int i=0;iint main()
{
n=read();k=read();
for(int i=1;i<=n;i++)
val[i]=read();
for(int i=1,x,y;i1);
dfs2(top[1]=1);
sort(stk+1,stk+stop+1,cmp);
for(int i=1;i<=stop;i++)
{
int u=stk[i];
root[u]=build(1,v[u].size(),u);
for(int j=0;jif(fa[u])
for(int j=0;j0][j])%md);
}
int q=read(),a,b;
char s[100];
while(q--)
{
scanf("%s",s+1);
if(s[1]=='C')
{
a=read();b=read();
for(int i=0;ifor(int i=0;ifor(;a;a=fa[top[a]])
change(a);
}
else
{
a=read();
for(int i=0;i1);
printf("%d\n",tmp[a]);
}
}
return 0;
}