zoukankan      html  css  js  c++  java
  • 2018牛客网暑假ACM多校训练赛(第二场)E tree 动态规划

    原文链接https://www.cnblogs.com/zhouzhendong/p/NowCoder-2018-Summer-Round2-E.html

    题目传送门 - 2018牛客多校赛第二场 E

    题意

      一棵 $n$ 个结点的树,每个点有一个点权,有 $m$ 次操作,每次操作有三种:

      1.  修改一个点的点权

      2.  修改一个点的父亲

      3.  询问包含某个点的所有大小为 $c$ 的连通块的点权乘积之和。

      $n,mleq 100000,cleq10 $

    题解

        

      

      
      以上题解图片摘自 laofu 题解。

      我再画几幅图介绍一下:

      注:箭头表示箭头尾端节点的 dp 对箭头指向节点有 dp 贡献。

        虚箭头表示中间省略一些有箭头连接的节点。

        虚线表示中线省略一些节点,但是没有箭头连接。

        每个图,最上面的节点表示往上走 $10$ 步到达的祖先。

        最下面的节点表示操作中的 $x$ 节点。

        注意一下修改和询问里面各有一个特殊箭头,意义自己理解。

     

      

      

     

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int read(){
    	char ch=getchar();
    	int x=0;
    	while (!isdigit(ch))
    		ch=getchar();
    	while (isdigit(ch))
    		x=(x<<1)+(x<<3)+ch-48,ch=getchar();
    	return x;
    }
    const int N=100005,mod=1e9+7;
    int n,m,val[N],fa[N];
    int dp[N][11];
    int Pow(int x,int y){
    	int ans=1;
    	for (;y;y>>=1,x=1LL*x*x%mod)
    		if (y&1)
    			ans=1LL*ans*x%mod;
    	return ans;
    }
    void DP(int a,int b){
    	if (!a||!b)
    		return;
    	for (int i=10;i>=1;i--)
    		for (int j=1;j<i;j++)
    			dp[a][i]=(1LL*dp[a][i]+1LL*dp[a][j]*dp[b][i-j])%mod;
    }
    void IDP(int a,int b){
    	if (!a||!b)
    		return;
    	for (int i=1;i<=10;i++)
    		for (int j=1;j<i;j++)
    			dp[a][i]=(1LL*dp[a][i]-1LL*dp[a][j]*dp[b][i-j])%mod;
    }
    int main(){
    	n=read(),m=read();
    	memset(dp,0,sizeof dp);
    	for (int i=1;i<=n;i++)
    		dp[i][1]=val[i]=read();
    	for (int i=2;i<=n;i++)
    		fa[i]=read();
    	for (int i=n;i>1;i--)
    		DP(fa[i],i);
    	while (m--){
    		int opt=read(),x=read(),y=read(),anc[15];
    		if (opt==0){
    			for (int i=1,j=x;i<=10;i++,j=fa[j])
    				anc[i]=j;
    			for (int i=10;i>1;i--)
    				IDP(anc[i],anc[i-1]);
    			int inv=Pow(val[x],mod-2);
    			val[x]=y;
    			for (int i=1;i<=10;i++)
    				dp[x][i]=1LL*dp[x][i]*inv%mod*y%mod;
    			for (int i=1;i<10;i++)
    				DP(anc[i+1],anc[i]);
    		}
    		if (opt==1){
    			for (int i=1,j=x;i<=10;i++,j=fa[j])
    				anc[i]=j;
    			for (int i=10;i>1;i--)
    				IDP(anc[i],anc[i-1]);
    			for (int i=2;i<10;i++)
    				DP(anc[i+1],anc[i]);
    			fa[x]=y;
    			for (int i=1,j=x;i<=10;i++,j=fa[j])
    				anc[i]=j;
    			for (int i=10;i>2;i--)
    				IDP(anc[i],anc[i-1]);
    			for (int i=1;i<10;i++)
    				DP(anc[i+1],anc[i]);
    		}
    		if (opt==2){
    			for (int i=1,j=x;i<=10;i++,j=fa[j])
    				anc[i]=j;
    			for (int i=10;i>1;i--)
    				IDP(anc[i],anc[i-1]);
    			for (int i=10;i>1;i--)
    				DP(anc[i-1],anc[i]);
    			printf("%d
    ",(dp[x][y]+mod)%mod);
    			for (int i=1;i<10;i++)
    				IDP(anc[i],anc[i+1]);
    			for (int i=1;i<10;i++)
    				DP(anc[i+1],anc[i]);
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    [C#]画图全攻略(饼图与柱状图)(转)
    ZedGraph控件的使用
    android PopupWindow实现从底部弹出或滑出选择菜单或窗口
    那两年炼就的Android内功修养
    android添加edittext后布局就不好用
    第三方应用分享到微信朋友圈功能
    android的微信签名
    Android开源库
    Android开发之Intent跳转到系统应用中的拨号界面、联系人界面、短信界面
    android 显示特殊符号
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/NowCoder-2018-Summer-Round2-E.html
Copyright © 2011-2022 走看看