Gym102431G Game on the Tree

Posted cjoiershiina-mashiro

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Gym102431G Game on the Tree相关的知识,希望对你有一定的参考价值。

结论:后手必胜当且仅当根节点为直径中点。

根节点为直径中点:
如果两人都在直径上移动,那么不论先手如何移动,后手总能移动到对称的位置。
如果先手移出了直径,设这一点与根节点的距离为(x),那么后手仍然回到直径上距离根节点(x)的点。
其它的情况先手只需移动至直径中点(当直径中点在边上时移动至该边的一端),然后按照上面的策略即可。

那么我们现在要求的就是直径中点为根节点的连通块个数。
(f_{u,i})表示(u)的子树中最大深度为(i)的子图的方案数,长链剖分优化dp即可。

#include<cstdio>
#include<cctype>
#include<vector>
#include<cstring>
#include<algorithm>
const int N=200007,P=1000000007;
int n,son[N],dep[N];std::vector<int>e[N];
struct node{int val,tag;node(){val=0,tag=1;}}pool[N*4],*now=pool,*f[N],g[N];
void inc(int&a,int b){a+=b-P,a+=a>>31&P;}
int add(int a,int b){return inc(a,b),a;}
int mul(int a,int b){return 1ll*a*b%P;}
int read(){int x=0,c=getchar();while(!isdigit(c))c=getchar();while(isdigit(c))(x*=10)+=c&15,c=getchar();return x;}
void dfs(int u,int fa){for(int v:e[u])if(v^fa)if(dfs(v,u),dep[v]+1>dep[u])dep[u]=dep[son[u]=v]+1;}
void alloc(int u){f[u]=now,now+=dep[u]+2;}
void modify(node*a,int x){a->tag=mul(a->tag,x),a->val=mul(a->val,x);}
void pushdown(node*a){if(a->tag^1) modify(a+1,a->tag),a->tag=1;}
void dp(int u,int fa)
{
    if(f[u][0].val=1,!son[u]) return ;
    f[son[u]]=f[u]+1,dp(son[u],u);
    for(int v:e[u])
    if(v^fa&&v^son[u])
    {
        alloc(v),dp(v,u);int len=dep[v]+1;
        if(u^1)
        {
        int r=1,s=1;
        for(int i=1;i<=len;++i) pushdown(f[u]+i),pushdown(f[v]+i-1),inc(r,f[u][i].val),f[u][i].val=add(mul(r,f[v][i-1].val),mul(s,f[u][i].val)),inc(s,f[v][i-1].val);
        modify(f[u]+len+1,s);
        }
        else
        {
        int r=1,s=1,t=0;
        for(int i=1,t1,t2;i<=len;++i)
        {
            pushdown(f[u]+i),pushdown(g+i),pushdown(f[v]+i-1);
            t1=add(mul(add(r,t),f[v][i-1].val),mul(s,f[u][i].val));
            t2=add(mul(s,g[i].val),mul(add(g[i].val,f[u][i].val),f[v][i-1].val));
            inc(r,f[u][i].val),inc(s,f[v][i-1].val),inc(t,g[i].val);
            f[u][i].val=t1,g[i].val=t2; 
        }
        modify(f[u]+len+ 1,s),modify(g+len+1,s);
        }
    }
}
int main()
{
    for(int t=read(),Case=1,ans;Case<=t;++Case)
    {
    n=read(),ans=1,memset(dep+1,0,n<<2),memset(son+1,0,n<<2),std::fill(g,g+n+1,node()),std::fill(pool,now,node()),now=pool;
    for(int i=1;i<=n;++i) e[i].clear();
    for(int i=1,u,v;i<n;++i) u=read(),v=read(),e[u].push_back(v),e[v].push_back(u);
    dfs(1,0),alloc(1),dp(1,0);
    for(int i=1;i<=n;++i) pushdown(g+i),inc(ans,g[i].val);
    printf("Case #%d: %d
",Case,ans);
    }
}

以上是关于Gym102431G Game on the Tree的主要内容,如果未能解决你的问题,请参考以下文章

gym/102059/problem/I. Game on Plane SG函数做博弈

模拟ECNA 2015 I What's on the Grille? (Codeforces GYM 100825)

Gym 100827G Number Game (博弈)

CF Gym Dice Game BFS 暴搜

Gym - 101438F Tree Game

GCD Guessing Game Gym - 100085G 猜数字 gcd