[启发式合并 DP] Atcoder ARC086E. Smuggling Marbles

比赛的时候想到了每层独立,但是不会搞…

官方题解

好像学到了关于深度的信息启发式合并的次数是 O(n) 的…
还有deque这种神奇的东西……像我以前都是set加上各种外层的标记……

果然还是太弱了

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>

using namespace std;

typedef pair<int,int> par;

const int N=200010,P=1e9+7,inv2=P+1>>1;

int n,cnt,G[N],dpt[N];
struct edge{
  int t,nx;
}E[N];
struct tp{
  int x,y,z;
  tp(){}
  tp(int a,int b,int c):x(a),y(b),z(c){}
};

inline void addedge(int x,int y){
  E[++cnt].t=y; E[cnt].nx=G[x]; G[x]=cnt;
}

inline int Pow(int x,int y){
  int ret=1;
  for(;y;y>>=1,x=1LL*x*x%P) if(y&1) ret=1LL*ret*x%P;
  return ret;
}

deque<tp> f[N];

void dfs(int x){
  int mx=0,smx=0;
  for(int i=G[x];i;i=E[i].nx){
    dfs(E[i].t); int v=E[i].t;
    if(f[v].size()>mx) smx=mx,mx=f[v].size();
    else smx=max(smx,(int)f[v].size());
    if(f[v].size()>f[x].size()) swap(f[x],f[v]);
    for(int j=0;j<f[v].size();j++){
      tp cur;
      cur.x=(1LL*f[x][j].x*f[v][j].y+1LL*f[v][j].x*f[x][j].y)%P;
      cur.y=1LL*f[x][j].y*f[v][j].y%P;
      cur.z=(1LL*f[x][j].x*f[v][j].x+1LL*f[x][j].x*f[v][j].z+1LL*f[x][j].y*f[v][j].z+1LL*f[x][j].z*f[v][j].x+1LL*f[x][j].z*f[v][j].y+1LL*f[x][j].z*f[v][j].z)%P;
      f[x][j]=cur;
    }
  }
  for(int i=0;i<smx;i++){
    f[x][i].y=(f[x][i].y+f[x][i].z)%P;
    f[x][i].z=0;
  }
  f[x].push_front(tp(inv2,inv2,0));
}

int main(){
  scanf("%d",&n);
  for(int i=1,x;i<=n;i++)
    scanf("%d",&x),addedge(x,i);
  dfs(0); int ans=0;
  for(int i=0;i<f[0].size();i++)
    ans=(ans+f[0][i].x)%P;
  ans=1LL*ans*Pow(2,n+1)%P;
  printf("%d\n",ans);
  return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值