zoukankan      html  css  js  c++  java
  • [cf1610I]Mashtali vs AtCoder

    考虑$k=1$时的问题(即AGC017D),可以参考这里(与后面有关系,建议阅读)

    而对于所有$k$,仍以1为根建树,并将整棵树分为若干个独立的问题——

    1.对于内部不存在固定点的极大子树,显然其再加上根父亲即是一个独立的问题,结合上题结论,这个问题的sg值为这棵子树的sg值+1

    2.对于去掉上述子树后剩下的部分,不妨看作一棵无根树,其满足度为1的节点均是固定点(其余点也可以是固定点,但事实上并不关心),且显然这也是一个独立的问题

    结论:这棵树的sg值为边数$mod\ 2$

    引理:对于存在固定点的树(不要求度为1的节点均是固定点),其sg值$\equiv $边数$(mod\ 2)$

    将引理和结论一起对节点个数归纳,考虑此时的一棵树,对其分类讨论:

    1.若该树所有度为1的节点均是固定点,考虑仅一次操作不会导致删除,因此去掉一条边后两个子问题的sg值异或和由引理$\not\equiv$边数$(mod\ 2)$,进而其$mex$可以取到边数$mod\ 2$,也即$sg\le $边数$mod\ 2$

    当边数为偶数时结论已经成立,考虑边数为奇数时,任取一个度为1的节点和距其最近的度不为2的节点(对于度为2的节点,总有唯一的出边,因此该点唯一),并在两者的路径上去边

    假设路径长度为$l$,将$l$分为$x$和$y$两段(其中$x+y=l-1$),这两段在新问题中都将作为第一种情况,而去掉后又是一个第2种情况,可以由归纳假设确定其sg值

    具体的,不难得到这个新问题的sg值为$x\oplus y\oplus (l\ mod\ 2)\oplus 1$,再对$l$的奇偶性分类讨论即可构造$x$和$y$使得其的值为0,也即$sg$恰为1(边数为奇数时)

    同时,显然对于引理也即成立

    2.若该树所有度为1的节点不均是固定点,将其按照之前的方式分为若干个独立的问题,注意到每一条边恰属于一个子问题,且每一个子问题点数均严格小于该树,由归纳假设成立

    结合sg函数的性质,将上述所有(独立的)问题sg值异或即为原问题的sg值

    实现上,预处理出所有子树的sg值以及$k=1$时的答案,考虑将$k$固定并维护答案

    考虑$k$向上所有子树内不存在(除$k$以外的)固定点的位置,假设依次为$a_{1},a_{2},...,a_{t}$(包括$k$本身),分析可得即将答案异或上$\bigoplus_{i=1}^{t}sg_{a_{i}}\oplus (sg_{a_{i}}+1)$,且第2部分的边数加上$t$

    这个如何找直接暴力即可,注意到一个节点至多被暴力找一次,均摊总复杂度为$o(n)$

    总复杂度为$o(n)$,可以通过

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 300005
     4 vector<int>v[N];
     5 int n,x,y,cnt,ans,f[N],vis[N],sg[N];
     6 void dfs(int k,int fa){
     7     f[k]=fa;
     8     for(int i=0;i<v[k].size();i++)
     9         if (v[k][i]!=fa){
    10             dfs(v[k][i],k);
    11             sg[k]^=sg[v[k][i]]+1;
    12         }
    13 }
    14 int main(){
    15     scanf("%d",&n);
    16     for(int i=1;i<n;i++){
    17         scanf("%d%d",&x,&y);
    18         v[x].push_back(y);
    19         v[y].push_back(x);
    20     }
    21     dfs(1,0);
    22     cnt=0,ans=sg[1],vis[1]=1;
    23     if (ans)printf("1");
    24     else printf("2");
    25     for(int i=2;i<=n;i++){
    26         for(int j=i;!vis[j];j=f[j]){
    27             vis[j]=1;
    28             cnt++,ans^=(sg[j]^(sg[j]+1));
    29         }
    30         if (ans^(cnt&1))printf("1");
    31         else printf("2");
    32     }
    33     return 0;
    34 }
    View Code
  • 相关阅读:
    linux(6)查看进程ps命令
    Python 基础03 序列
    Python 基础02 基本数据类型
    Python基础01 Hello World!
    Linux vi/vim
    Laravel 的HTTP控制器
    Laravel 下的伪造跨站请求保护 CSRF#
    Linux 磁盘管理
    Linux 用户he用户组管理
    Linxu 用户和用户组管理1
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/15637537.html
Copyright © 2011-2022 走看看