题意:给定一颗树,每个节点有权值,再给定三个操作,操作0是改变点权值,操作1是改变某点的父亲,操作2是询问包含某点的大小为k(k<=10)的联通块的价值,一个联通块的价值定义为该联通快上点权的乘积
看起来很像数据结构题,其实竟然是DP??
一个比较好的切入点是k<=10,这个带来的一个便利是,对于一个点的修改,仅涉及到他的10代祖先,那这样可以直接维护子树信息,再暴力更新维护
设d[i][j]为i为根的子树中,包含i的大小为j的联通块的价值
如果没有修改显然一遍dfs就行了。。然而带修的dp好像至今还没见过。。然后懵逼中。。
但是这个背包DP有一个很好的性质就是可撤销性,我们做这个背包做的是01背包,而撤销的方式正好是完全背包
即合并时为
dec(i,10,2)inc(j,1,i-1)d[i]+=d[i-j]*o.d[j]%inf,d[i]%=inf;
撤销为
inc(i,2,10)inc(j,1,i-1)d[i]+=inf-d[i-j]*o.d[j]%inf,d[i]%=inf;
那么对操作0,修改的时候直接去掉当前节点为根的子树,由于这个节点的背包一定包含他,即总是有他的乘积,直接除一下乘一下即可。。
对操作1,修改的时候就直接去子树和加子树
对操作2,把10代祖先去掉对应子树再合并一下就可以了
/**
* ┏┓ ┏┓
* ┏┛┗━━━━━━━┛┗━━━┓
* ┃ ┃
* ┃ ━ ┃
* ┃ > < ┃
* ┃ ┃
* ┃... ⌒ ... ┃
* ┃ ┃
* ┗━┓ ┏━┛
* ┃ ┃ Code is far away from bug with the animal protecting
*