题意:给定一颗树,每个节点有权值,再给定三个操作,操作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
* ┃ ┃ 神兽保佑,代码无bug
* ┃ ┃
* ┃ ┃
* ┃ ┃
* ┃ ┃
* ┃ ┗━━━┓
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━┳┓┏┛
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define eps 1e-8
#define succ(x) (1LL<<(x))
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define mid ((x+y)/2)
#define NM 100015
#define nm 200005
#define pi 3.1415926535897931
using namespace std;
const ll inf=1e9+7;
ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}
struct edge{int t;edge*next;}e[nm],*h[NM],*o=e;
void add(int x,int y){o->t=y;o->next=h[x];h[x]=o++;}
int n,a[NM],m,_x,_y,_t,f[NM],c[NM],tot;
ll qpow(ll x,ll t){return t?qpow(sqr(x)%inf,t>>1)*(t&1?x:1)%inf:1LL;}
struct pack{
ll d[11];
void operator+=(const pack&o){
dec(i,10,2)inc(j,1,i-1)d[i]+=d[i-j]*o.d[j]%inf,d[i]%=inf;
}
void operator-=(const pack&o){
inc(i,2,10)inc(j,1,i-1)d[i]+=inf-d[i-j]*o.d[j]%inf,d[i]%=inf;
}
pack operator+(const pack&o){
pack s=*this;s+=o;return s;
}
pack operator-(const pack&o){
pack s=*this;s-=o;return s;
}
}d[NM];
void dfs1(int x){
link(x)if(j->t!=f[x]){
dfs1(j->t);
d[x]+=d[j->t];
}
}
int main(){
//freopen("data.in","r",stdin);
n=read();m=read();
inc(i,1,n)a[i]=d[i].d[1]=read();
inc(i,2,n)f[i]=read(),add(f[i],i);
inc(i,1,n)if(!f[i])dfs1(i);
while(m--){
_t=read();_x=read();_y=read();tot=0;
for(int i=1,x=_x;x&&i<=10;x=f[x],i++)c[++tot]=x;
if(_t==0){
dec(i,tot-1,1)d[f[c[i]]]-=d[c[i]];
ll t=_y*qpow(a[_x],inf-2)%inf;
inc(i,1,10)(d[_x].d[i]*=t)%=inf;
a[_x]=_y;
inc(i,1,tot-1)d[f[c[i]]]+=d[c[i]];
}else if(_t==1){
dec(i,tot-1,1)d[c[i+1]]-=d[c[i]];
inc(i,2,tot-1)d[c[i+1]]+=d[c[i]];
tot=0;
for(int i=1,x=_y;x&&i<=10;x=f[x],i++)c[++tot]=x;
dec(i,tot-1,1)d[c[i+1]]-=d[c[i]];
f[_x]=_y;d[_y]+=d[_x];
inc(i,1,tot-1)d[c[i+1]]+=d[c[i]];
}else{
if(tot==1){printf("%lld\n",d[_x].d[_y]);continue;}
pack s=d[c[tot]]-d[c[tot-1]];
dec(i,tot-2,1)s=(d[c[i+1]]-d[c[i]])+s;
s=d[_x]+s;
printf("%lld\n",s.d[_y]);
}
}
return 0;
}
链接:https://www.nowcoder.com/acm/contest/140/E
来源:牛客网
tree
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
题目描述
There is a tree with n(n<=100000) nodes.The root is a node with number 1.
The i-th node has a value val[i](0<val[i]<1000000000+7).
Define the value of a connected component as the product of each node's value.
White Cloud has 3 types of operation.
The first operation is to change a node's value.
The second operation is to change a node's father.
The third operation is to give 2 integers b and c, denoting querying the sum of value of all connected components which contains node b of size c.
输入描述:
The first line of input contains 2 integers n and m(n,m<=100000). In the next line, there are n integers, denoting val[1..n]. In the next line, there are n-1 integers, denoting the father from the 2-th node to the n-th node. In the next m lines, the first number a is the type of operation. if a=0, the next 2 integers b and c(1 <= b <= n,0<c<1e9+7) denote changing the value of b to c. if a=1, the next 2 integers b and c(1 <= b,c <= n,c is not in the subtree of b) denote changing the father of b to c. if a=2, the next 2 integers b and c(1 <= b <= n,0<c <= 10) denote querying the sum of value of all connected components which contains node b of size c.
输出描述:
For each operation, if a=2, print a single line containing the answer modulo 1000000000+7.
示例1
输入
3 3 1 2 3 1 1 2 1 2 2 1 3 2 2 3
输出
5 6 6