列表

详情


NC14946. 白云的树

描述

白云有一棵n个结点的树,以1号结点为根,这棵树的每个结点有一个权值vali
定义一个连通块的喜爱度为块内所有结点权值的乘积。
白兔有很多疑问,每个疑问有两个参数k,s,表示询问所有经过点k的大小为s的连通块的喜爱度之和。
白云会定期对树做一些修改。

输入描述

第一行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]);
		}
	}
}

上一题