2019 CCPC-Final G.Game on the Tree(长链剖分+DP)

题目大意

两个人在一个以1为根的树上玩游戏,一开始硬币在1。然后每一轮,如果当前硬币在u,当前的人可以选择一个v把硬币移动到v,条件是移动的距离要大于上一轮的人移动的距离。第一个人可以随便移动。
问给出的树有多少个以1为根的子图可以让后手必胜。
n ≤ 2 e 5 n\le2e5 n2e5

解题思路

这题很容易推出来当1是树直径的中点的时候后手必胜。
然后想要得到1是树直径中点的方案数,可以先得到1的每个儿子 v v v的深度为 i ( 0 < = i < l e n [ v ] ) i(0<=i<len[v]) i(0<=i<len[v])的方案数,再根据这个 d p dp dp
f ( v , j ) f(v,j) f(v,j)表示结点 v v v最大深度为 j j j的子图方案数进行DP。
利用长链剖分优化这个转移,注意到长链剖分过程中,轻儿子转移完对应的深度之后,父节点还有一些数据是需要更新的。那么我们开一个额外的懒标记数组去标记,每当要用到对应的值的时候我们就更新它并让懒标记向后传递。
得到了所有的 f ( v , j ) f(v,j) f(v,j)之后我们用 d p ( i , 0 ) dp(i,0) dp(i,0)表示只有根1只有一个子树最大深度为 i i i且所有子树中最大的深度为 i i i的方案数, d p ( i , 1 ) dp(i,1) dp(i,1)表示根1有大于等于2个子树最大深度为 i i i且所有子树中最大深度为 i i i的方案数。和前面类似利用懒标记去转移。
ps:一定要注意懒标记的细节……多传或者漏传都会wa傻眼
代码后面提供1组测试数据

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 2e5 + 50;
const ll mod = 1e9 + 7;
ll temp[maxn*8], *f[maxn], *ex[maxn], *sz[maxn], *id, dp[maxn][2], exdp[maxn][2];
int len[maxn], son[maxn];
vector<int> g[maxn];
int n;
void DFS(int u, int fa){
   
    
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值