nowcoder2多校E(树型DP+可逆背包DP)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qkoqhh/article/details/83584772

题意:给定一颗树,每个节点有权值,再给定三个操作,操作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

猜你喜欢

转载自blog.csdn.net/qkoqhh/article/details/83584772