zoukankan      html  css  js  c++  java
  • [atAGC004F]Namori

    考虑树的情况,将其以任意一点为根建树

    对于每一个节点,考虑其要与父亲操作几次才能使子树内均为黑色,这可以用形如$(0/1,x)$的二元组来描述,其中0/1即表示其要求操作时父亲是白色/黑色且要操作$x$次

    考虑一个叶子,其二元组显然为$(0,1)$,接下来每一个点即可以交替将儿子中的$(0/1,x)$变为$(0/1,x-1)$

    (先以白色点操作$(0,x)$,操作后变为黑色,再以黑色点操作$(1,x)$……)

    最终,将剩下的合并(第一元必然相同,第二元直接相加),那么该节点即需在另一个状态下与其父亲操作,另外最后还需要额外以白色操作一次

    换言之,假设合并后的二元组为$(p,x)$(其中$xge 0$,且若$x=0$则不妨令$p=1$),那么根据上述分析该点上的二元组即为$egin{cases}(1,x-1)&(p=0)\(0,x+1)&(p=1)end{cases}$

    关于答案,若根节点上的二元组第二维不为0显然无解,否则考虑每一个节点与父亲操作的次数,即为该点上二元组的第二维,显然将对所有节点求和即可

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

    事实上,上述二元组可以直接用一个整数描述,即将$(0/1,x)$分别看作$pm x$,则转移即$g_{i}=1-sum_{son}g_{son}$,最终答案也即$sum_{i}|g_{i}|$(特别的,若$g_{rt} e 0$则无解,其中$rt$为根),两者等价性显然

    考虑基环树的情况,将整个基环当作根,并删去基环上的边后得到若干棵子树(仍以基环上的点为根),对每一棵子树仍用上述方式计算得到根的$g_{i}$,最终即可得到一个长为$l$(其中$l$为环长)的序列

    记该序列为$a_{i}$,此时问题即将相邻两个$a_{i}$(注意首尾也相连)同时$pm 1$,并使得最终$a_{i}$均为0

    若$sum_{i=1}^{l}a_{i} otequiv 0(mod 2)$显然无解(操作不改变奇偶性),否则对$l$的奇偶性分类讨论:

    1.若$l$为奇数,考虑奇偶数位的差值,除了首尾操作以外不会改变该值,而首尾操作恰会使该值$pm 2$,由此不难确定首尾操作形式即次数,进而操作后将首尾断开,从前往后依次使得$a_{i}$为0即可(最终$a_{l}$一定为0)

    2.若$l$为偶数,注意到奇数位和偶数位差值不变,因此初始两者必须相同

    枚举首尾操作使得$a_{1}$和$a_{l}$同时减$z$,之后即将首尾断开并从前往后依次使得$a_{i}$为0

    不难得到(首尾断开后)$a_{i}$清0的代价即$sum_{i=1}^{l}abs{sum_{j=1}^{i}(-1)^{i-j}a_{j}}$,对每个$i$预处理出该值为$S_{i}$(减去$z$前),那么修改的影响即将奇数项减去$z$、偶数项(除$l$以外)加上$z$

    将$S_{i}$偶数项取相反数(奇数项不变)得到$S'_{i}$,此时即求$|S_{l}|+min_{z}left(sum_{i=1}^{l-1}|S'_{i}-z|+|z| ight)$

    最后一项可以看作$|0-z|$,那么显然取$z$为$S'_{i}$(其中$1le ile l-1$)和0的中位数即可

    时间复杂度也为$o(n)$,可以通过

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 100005
     4 #define ll long long
     5 vector<int>v0,v[N];
     6 int n,m,x,y,st[N],vis[N];
     7 ll sum,ans,a[N],g[N];
     8 void dfs(int k,int fa){
     9     st[++st[0]]=k,vis[k]=1;
    10     for(int i=0;i<v[k].size();i++)
    11         if (v[k][i]!=fa){
    12             if (!vis[v[k][i]])dfs(v[k][i],k);
    13             else{
    14                 if (vis[v[k][i]]==2)continue;
    15                 for(int j=st[0];st[j]!=v[k][i];j--)v0.push_back(st[j]);
    16                 v0.push_back(v[k][i]);
    17             }
    18         }
    19     st[0]--,vis[k]=2;
    20 }
    21 void dp(int k){
    22     vis[k]=g[k]=1;
    23     for(int i=0;i<v[k].size();i++)
    24         if (!vis[v[k][i]]){
    25             dp(v[k][i]);
    26             g[k]-=g[v[k][i]];
    27         }
    28 }
    29 int main(){
    30     scanf("%d%d",&n,&m);
    31     for(int i=1;i<=m;i++){
    32         scanf("%d%d",&x,&y);
    33         v[x].push_back(y);
    34         v[y].push_back(x);
    35     }
    36     dfs(1,0);
    37     memset(vis,0,sizeof(vis));
    38     if (v0.empty()){
    39         dp(1);
    40         if (g[1])printf("-1
    ");
    41         else{
    42             for(int i=1;i<=n;i++)ans+=abs(g[i]);
    43             printf("%lld
    ",ans);
    44         }
    45         return 0;
    46     }
    47     int l=v0.size();
    48     for(int i=0;i<l;i++)vis[v0[i]]=2;
    49     for(int i=0;i<l;i++){
    50         dp(v0[i]);
    51         a[i+1]=g[v0[i]];
    52     }
    53     for(int i=1;i<=n;i++)ans+=abs(g[i]);
    54     for(int i=1;i<=l;i++){
    55         ans-=abs(a[i]);
    56         if (i&1)sum+=a[i];
    57         else sum-=a[i];
    58     }
    59     if (sum&1){
    60         printf("-1
    ");
    61         return 0;
    62     }
    63     if (l&1){
    64         ans+=(abs(sum)>>1);
    65         a[1]-=(sum>>1),a[l]-=(sum>>1);
    66         for(int i=1;i<l;i++){
    67             ans+=abs(a[i]);
    68             a[i+1]-=a[i];
    69         }
    70         printf("%lld
    ",ans);
    71         return 0;
    72     }
    73     if (sum){
    74         printf("-1
    ");
    75         return 0;
    76     }
    77     for(int i=1;i<=l;i++)a[i]-=a[i-1];
    78     ans+=abs(a[l]),a[l]=0;
    79     for(int i=2;i<=l;i+=2)a[i]=-a[i];
    80     sort(a+1,a+l+1);
    81     for(int i=1;i<=l;i++)
    82         if (i<=(l>>1))ans+=a[l>>1]-a[i];
    83         else ans+=a[i]-a[l>>1];
    84     printf("%lld
    ",ans);
    85     return 0;
    86 }
    View Code
  • 相关阅读:
    八数码难题 (codevs 1225)题解
    小木棍 (codevs 3498)题解
    sliding windows (poj 2823) 题解
    集合删数 (vijos 1545) 题解
    合并果子 (codevs 1063) 题解
    等价表达式 (codevs 1107)题解
    生理周期 (poj 1006) 题解
    区间 (vijos 1439) 题解
    区间覆盖问题 题解
    种树 (codevs 1653) 题解
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/15438467.html
Copyright © 2011-2022 走看看