首页 > 其他分享 >【题解】[POI2015] MOD

【题解】[POI2015] MOD

时间:2023-09-13 12:01:35浏览次数:63  
标签:chain fx 题解 up POI2015 down del now MOD

传送门

挺恶心的感觉这题代码,就来写写题解。

题目分析

假设我们现在要删掉 \((x,y)\) 这条边,思考这样能贡献的最大或最小直径。

不难发现,此时一棵树分裂成了两棵树 \(a,b\),我们令它们的直径分别为 \(la,lb\)。将两棵树内直径的任意端点连起来,发现 \(maxi=la+lb+1\)。将两棵树内直径的中点连起来,发现 \(mini=\left\lceil\dfrac{la}{2}\right\rceil+\left\lceil\dfrac{lb}{2}\right\rceil+1\)。所以我们的目标就是维护这两个值。

假装现在的根节点是 \(1\)(其实是谁大概都无所谓),再考虑维护这两个值,也就是要维护 \(dp[x]\) 表示在 \(x\) 的子树内的直径,\(del[x]\) 表示删掉 \(x\) 和 \(fa[x]\) 这条边后在 \(x\) 的子树外的直径。分别考虑怎么维护。

\(dp[x]\) 的维护可以套路地想到维护 \(chain\_down[x][0/1]\) 表示在 \(x\) 的子树内的最长链和次长链。

\(del[x]\) 的维护是个难点。我们考虑维护 \(chain\_up[x]\) 表示从 \(x\) 开始向上的最长链。发现如果删掉了 \(x\),那么 \(del[x]\) 可能会有以下几种情况(\(fx\) 为 \(x\) 的父亲):

  1. 是 \(dp[fx]\),也就是 \(chain\_down[fx][0]+chain\_down[fx][1]\)。但此时要满足子树 \(x\) 不是 \(fx\) 的最长链或者次长链,所以我们还要维护一个次次长链,分类讨论一下即可。所以次次长链加最长链什么的情况都放在这一种情况内了。
  2. 是 \(chain\_up[fx]+chain\_down[fx][0]\),因为此时类似于是以 \(fx\) 为一个根节点嘛,所以就找外面的一条链和里面的一条链即可。特判一下 \(x\) 就是最长链的情况,这时候是加上次长链。
  3. 是 \(fx\) 的一个子节点内的直径。此时也要判断一下 \(x\) 是不是这个直径最长的子节点,所以我们还需要维护一个 \(dia[fx][0/1]\) 维护在 \(x\) 的子节点的子树内的最长直径和次长直径。

现在我们明确了要维护哪些值,然后再考虑怎么维护。

我们发现 \(fa[x],chain\_down[x][0/1/2],dia[x][0/1]\) 的处理不需要依赖其他数组,我们就可以在第一遍 dfs 内维护这些值。

感觉这题理解哪些数组是干什么的很重要,所以我再重新列一下好了(

  1. \(fa[x]\):\(x\) 的父亲
  2. \(deep[x]\):\(x\) 的深度(后面有用)
  3. \(chain_up[x]\):从 \(x\) 开始向上的最长链
  4. \(chain_down[x][0/1/2]\):在 \(x\) 的子树内的最长链,次长链和次次长链
  5. \(del[x]\):删掉 \(x\) 和 \(fx\) 这条边后在 \(x\) 的子树外的直径
  6. \(dia[x][0/1]\):在 \(x\) 的子节点的子树内的最长直径和次长直径
  7. \(dp[x]\):在 \(x\) 的子树内的直径
void dfs1(int x,int fx){
    deep[x]=deep[fx]+1;
    fa[x]=fx;
    for(int i=head[x];i;i=edge[i].nex){
        int v=edge[i].to;
    //    chain_up[v]=chain_up[x]+1;
        if(v==fx) continue;
        dfs1(v,x);
        dp[x]=max(dp[x],dp[v]);

        int now=chain_down[v][0]+1;
        if(now>chain_down[x][0]){
            chain_down[x][2]=chain_down[x][1];
            chain_down[x][1]=chain_down[x][0];
            chain_down[x][0]=now;
        }
        else if(now>chain_down[x][1]){
            chain_down[x][2]=chain_down[x][1];
            chain_down[x][1]=now;
        }
        else if(now>chain_down[x][2])
            chain_down[x][2]=now;

        now=dp[v];
        if(now>dia[x][0]){
            dia[x][1]=dia[x][0];
            dia[x][0]=now;
        }
        else if(now>dia[x][1])
            dia[x][1]=now;
    }
    dp[x]=max(dp[x],chain_down[x][0]+chain_down[x][1]);
}

剩下的数组在第二次 dfs 内处理

void dfs2(int x,int fx){
    if(fx){
        int now=dp[x]+del[x]+1;
        if(maxi.v<now){
            maxi.v=now;
            maxi.xa=x,maxi.ya=fx;
        }
        now=max(max(del[x],dp[x]),(1+del[x])/2+(1+dp[x])/2+1);
        if(mini.v>now){
            mini.v=now;
            mini.xa=x,mini.ya=fx;
        }
    }

    for(int i=head[x];i;i=edge[i].nex){//删掉v这个点
        int v=edge[i].to;
        if(v==fx) continue;
        chain_up[v]=chain_up[x]+1;
        del[v]=del[x];

        int now=chain_down[v][0]+1;
        if(now==chain_down[x][0]){
            del[v]=max(del[v],max(chain_down[x][1]+chain_down[x][2],chain_up[x]+chain_down[x][1]));
            chain_up[v]=max(chain_up[v],chain_down[x][1]+1);
        }
        else if(now==chain_down[x][1]){
            del[v]=max(del[v],max(chain_down[x][0]+chain_down[x][2],chain_up[x]+chain_down[x][0]));
            chain_up[v]=max(chain_up[v],chain_down[x][0]+1);
        }
        else{
            del[v]=max(del[v],max(chain_down[x][0]+chain_down[x][1],chain_up[x]+chain_down[x][0]));
            chain_up[v]=max(chain_up[v],chain_down[x][0]+1);
        }
        now=dp[v];
        if(now==dia[x][0])
            del[v]=max(del[v],dia[x][1]);
        else
            del[v]=max(del[v],dia[x][0]);

        dfs2(v,x);
    }
}

现在我们求出了最大直径和得到它需要删哪两个节点,最小直径和得到它需要删哪两个节点。接下来就要求要接哪两个节点。

先考虑最小直径的,之前分析的是两条直径的中点。所以我们可以分别求两遍 dfs 求出两条直径的端点,再暴力求出中点即可。

再考虑最大直径的,这个比最小直径好处理,随便跑下 dfs 找到一个端点即可。

总结

  1. 先根据数据范围求出时间复杂度,根据这个看要遍历什么才能得到答案,比如此题就是遍历要删掉的边(点)
  2. 知道要求什么之后思考要维护什么
  3. 知道要维护什么之后,注意注释一下(,不要忘了
  4. 维护的东西太多之后,注意思考明确每个数组是干嘛的,明确整体思路。

标签:chain,fx,题解,up,POI2015,down,del,now,MOD
From: https://www.cnblogs.com/Arcka/p/17699216.html

相关文章

  • 洛谷 CF707C Pythagorean Triples の 题解
    这道题是一道数论题,不可用暴力通过,因为输入范围极大,基本上循环是不能在这道题上使用的了。前面大佬们讲的我听不懂,于是在教练的帮助下,我利用题面给出的多组样例找到了规律。在此之前,我们先设输入的数为\(n\)。\(n\)分三种情况。\(n\)是奇数;\(n\)是偶数;\(n\)小于等于......
  • 洛谷 P9503『MGOI』Simple Round I | B. 魔法照相馆 の 题解
    这道题是一道模拟题,坑点不多,但是细节特多,所以导致大部分人\(A\)不了这道题。这道题我也写了注释,如果思路没明白可以看代码和注释的。先创建一个长度为\(3\)的字符串\(s1\),这个字符串的意思就是模拟现在的这几个幕布的情况,这里分了四个字符代表着四种情况,详细如下该字符串......
  • 洛谷 P9502 『MGOI』Simple Round I | A. 魔法数字 の 题解
    直接用pow()函数暴力判断即可,一旦不符合条件就立即跳出循环,要注意开longlong或unsignedlonglong。#include<iostream>#include<cmath>usingnamespacestd;unsignedlonglongn,num;intmain(){cin>>n;for(unsignedlonglongi=2;i<=n;i+=......
  • 洛谷 UVA10852 Less Prime の 题解
    这道题更像是结论题,因为他要推一个小结论,才能做出这道题。大概思路是先打个素数表,存到数组\(a\)内,\(cnt\)是素数表的最后一个元素的下标。之后循环\(M\)次去输入\(N\),每次输入\(N\)之前都要定义两个变量,分别是\(mx\),存\(n-p\cdotx\)的最大值,\(ans\)则是当\(n-......
  • 洛谷 UVA10714 Ants の 题解
    这道题只有一个点比较难想。大概思路就是先输入个$t$,表示要跑几轮,后面的照常输入。因为蚂蚁都是一样的,所以两个蚂蚁碰面的时候相互穿过和各自掉头是没有区别的,我们按照前者模拟就好,其余思路暴力求解即可。#include<iostream>#include<cmath>usingnamespacestd;intt;in......
  • 洛谷 AT_past202005_i 行列操作 の 题解
    这道题最难的点在于用什么方法存储矩阵$a$和一个特殊的操作方式。要存矩阵$a$,最先想到的是二维数组,但是二维数组开不到$1\len\le10^5$,所以可以用一个长度为$2\cdotn$的一维数组$m$来存。当$i\len$时,让一维数组$m_{i}$负责存第$i$行的内容;而当$n+1\lei......
  • 洛谷 AT_maximum_cup_2018_a フィギュアスケート界の貴公子埼大選手 の 题解
    这道题是一道水题,所以你的代码很可能与我相似或相同,如果你的代码出现了问题,你很可能在我的题解里找出答案。这道题大概思路是一旦$10$秒后运动员会接触到毛绒玩具,那么就加上在这个点上毛绒玩具的数量。但是!这道题有一道巨坑的点!由于这道题比较远古,所以说你即使是正解,你也要在......
  • npm 找不到全局global安装的模块module
     npmlist-global 可以找到已经安装的module 1.首先找到我们自己设置的全局仓库的目录npmconfiggetprefix  2.查看当前node能找到的module仓库或目录:运行node,输入module.paths   可以看到并没有上边的全局仓库地址  3.打开系统设置,配置环境变量......
  • IIS上缺少 AspNetCoreModuleV2 如何解决
    实际上是少了装了.NetCoreSDK需要找到自己的程序使用的.NetCore对应版本进行下载https://dotnet.microsoft.com/en-us/download/dotnet/3.0只装Hosting就行了......
  • 【题解】Educational Codeforces Round 141(CF1783)
    评价:educationalA.MakeitBeautiful题目描述:如果一个数组中存在一个数恰好等于该数前面所有数之和,那么这个数组就是丑的。如果一个数组不是丑的,就是美的。比如说:数组$[6,3,9,6]$是丑的,因为\(9=6+3\);数组$[5,5,7]$是丑的,因为第二个\(5=5\)。数组$......