这个东西\(80\)分暴力\(O(NQs^2)\)很显然,直接每次询问跑一次树上背包即可。

然后考虑这个随机有什么用

这个东西树高是\(logn\),每个节点的孩子个数期望\(e\)

那么每次修改暴力跳修改,然后每次查询暴力跳询问即可。

但是这个东西还可以不依赖树随机,因为最大只有\(10\),所以跳\(10\)层就可以回来了。

时间复杂度\(O(nlogns^2)\)

code:


#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define ll long long
#define db double
#define N 100000
#define M 50000
#define mod 1000000007
#define mod2 39989
#define eps (1e-7)
#define U unsigned int
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
using namespace std;
int n,m,op,x,y=10,val[N+5],fa[N+5];ll F[N+5][11],G[N+5][11];
struct yyy{int to,z;}tmp;
struct ljb{
int head,h[N+5];yyy f[N+5<<1];
I void add(int x,int y){f[++head]=(yyy){y,h[x]};h[x]=head;}
}s;
I void merge(ll *A,ll *B){
re int i,j;for(i=10;i;i--){
for(j=1;j<=10-i;j++) A[i+j]=(A[i]*B[j]+A[i+j])%mod;
}
}
I void insert(int x,int y){
re int i,j,h;val[x]=y;for(;x;x=fa[x]){
Me(F[x],0);F[x][1]=val[x];for(i=s.h[x];i;i=tmp.z)tmp=s.f[i],merge(F[x],F[tmp.to]);
}
}
I void find(int x,int last){
yyy tmp;Me(G[x],0);G[x][1]=val[x];for(int i=s.h[x];i;i=tmp.z) tmp=s.f[i],tmp.to^last&&(merge(G[x],F[tmp.to]),0);
if(x==1) return;find(fa[x],x);merge(G[x],G[fa[x]]);
}
I void read(int &x){
char s=Gc();x=0;while(s<'0'||s>'9') s=Gc();
while(s>='0'&&s<='9') x=x*10+s-48,s=Gc();
}
I void Make(int x,int last){
F[x][1]=val[x];yyy tmp;for(int i=s.h[x];i;i=tmp.z) tmp=s.f[i],tmp.to^last&&(Make(tmp.to,x),merge(F[x],F[tmp.to]),0);
}
int main(){
freopen("tree.in","r",stdin);freopen("tree.out","w",stdout);
re int i,j;scanf("%d%d",&n,&m);for(i=1;i<=n;i++) read(val[i]);for(i=2;i<=n;i++) read(fa[i]),s.add(fa[i],i);
Make(1,0);while(m--){
read(op);read(x);read(y);if(!op) insert(x,y);else find(x,0),printf("%lld\n",G[x][y]);
}
}