NC14946. 白云的树
描述
输入描述
第一行1个整数n,Q,表示树的结点个数和事件个数。
第二行n个整数表示val1 ... n。
第三行n-1个整数表示2...n号结点的父亲。接下来Q行,第一个数为op∈{0,1},如果op=0表示白云要对某个结点的权值进行修改,接下来两个数k,c表示把结点k的权值修改为c。如果op=1表示白兔的疑问,接下来两个数k,s。
输出描述
对于op=1,每行一个数表示答案。答案对109+7取模。
示例1
输入:
15 15 6 4 8 6 8 9 10 9 2 9 8 3 3 6 2 1 1 1 3 1 3 6 5 3 10 9 7 9 13 1 13 8 1 2 4 1 12 8 1 11 2 0 2 9 0 11 4 1 3 6 0 4 5 1 13 7 1 8 2 1 7 6 1 7 8 0 5 5 0 1 7 1 1 6
输出:
128592000 11304 35520768 72 10402608 16325280 81 6030720 359079840 8686888
C++14(g++5.4) 解法, 执行用时: 896ms, 内存消耗: 6264K, 提交时间: 2019-07-10 21:28:43
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; int gi(){ int x=0,w=1;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')w=0,ch=getchar(); while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return w?x:-x; } const int N=1e5+5; const int mod=1e9+7; int n,m,fa[N],f[N][13],s[N]; int fastpow(int x,int y){ int res=1; while(y){if(y&1)res=1ll*res*x%mod;x=1ll*x*x%mod;y>>=1;} return res; } void work(int x,int y){ for(int i=10;i;--i) for(int j=1;i+j<=10;++j) f[x][i+j]=(f[x][i+j]+1ll*f[x][i]*f[y][j])%mod; } void undo(int x,int y){ for(int i=1;i<=10;++i) for(int j=1;i+j<=10;++j) f[x][i+j]=(f[x][i+j]+1ll*(mod-f[x][i])*f[y][j])%mod; } int main(){ n=gi();m=gi(); for(int i=1;i<=n;++i)f[i][1]=gi(); for(int i=2;i<=n;++i)fa[i]=gi(); for(int i=n;i>1;--i)work(fa[i],i); while(m--) if(gi()){ int x=gi(),y=gi(),top=0; for(int i=x;i;i=fa[i])s[++top]=i; // for(int i=1;i<=top;++i)printf("%d ",s[i]);puts(""); // for(int i=1;i<=10;++i)printf("%d ",f[1][i]);puts(""); // for(int i=1;i<=10;++i)printf("%d ",f[2][i]);puts(""); for(int i=top-1;i;--i)undo(s[i+1],s[i]),work(s[i],s[i+1]); // for(int i=1;i<=10;++i)printf("%d ",f[1][i]);puts(""); // for(int i=1;i<=10;++i)printf("%d ",f[2][i]);puts(""); printf("%d\n",f[x][y]); for(int i=1;i<top;++i)undo(s[i],s[i+1]),work(s[i+1],s[i]); }else{ int x=gi(),y=gi(),top=0; for(int i=x;i;i=fa[i])s[++top]=i; for(int i=top-1;i;--i)undo(s[i+1],s[i]); y=1ll*y*fastpow(f[x][1],mod-2)%mod; for(int i=1;i<=10;++i)f[x][i]=1ll*f[x][i]*y%mod; for(int i=1;i<top;++i)work(s[i+1],s[i]); } return 0; }
C++11(clang++ 3.9) 解法, 执行用时: 1393ms, 内存消耗: 20864K, 提交时间: 2018-01-19 21:38:06
#include<bits/stdc++.h> using namespace std; template <typename T> void chmax(T &x,const T &y) { if(x<y)x=y; } typedef long long ll; #define rep(i,l,r) for(int i=l;i<=r;++i) #define per(i,r,l) for(int i=r;i>=l;--i) const int N=1e5+5,S=10+1; const int D=1e9+7; ll MI(ll x,int y,int D) { ll ans=1; while(y) { if(y&1)ans=ans*x%D; x=x*x%D;y>>=1; } return ans; } int fa[N],t[N],v[N]; struct edge { int to,next; }; edge l[N*2];int e; ll dp[N][S]; ll DP[N][S]; ll *dfs(int x,int s,int fr) { if(fr==fa[x])return DP[x]; dp[x][1]=v[x]; if(s==1)return dp[x]; rep(j,2,s)dp[x][j]=0; for(int i=t[x];i;i=l[i].next) { int y=l[i].to; if(y==fr)continue; ll *dpy=dfs(y,s-1,x); per(j,s,2) rep(k,1,j-1)(dp[x][j]+=dp[x][k]*dpy[j-k])%=D; } return dp[x]; } void up(int x) { rep(j,2,S-1) DP[x][j]=0; for(int i=t[x];i;i=l[i].next) { int y=l[i].to; if(y==fa[x])continue; per(j,S-1,2) rep(k,1,j-1)(DP[x][j]+=DP[x][k]*DP[y][j-k])%=D; } } int main() { //freopen("1.in","r",stdin); int n,tt; cin>>n>>tt; rep(i,1,n)scanf("%d",v+i); rep(i,2,n) { scanf("%d",&fa[i]); l[++e]=(edge){i,t[fa[i]]};t[fa[i]]=e; l[++e]=(edge){fa[i],t[i]};t[i]=e; } per(i,n,1) { DP[i][1]=v[i]; up(i); } while(tt--) { int op; scanf("%d",&op); if(op==0) { int x,c; scanf("%d%d",&x,&c); DP[x][1]=v[x]=c; for(;x;x=fa[x]) { up(x); } } else { int k,s; scanf("%d%d",&k,&s); //dfs(k,s,0); printf("%d\n",dfs(k,s,0)[s]); } } }