bzoj 4871: [Shoi2017]摧毁“树状图”

4871: [Shoi2017]摧毁“树状图”

Time Limit: 25 Sec  Memory Limit: 512 MB
Submit: 53  Solved: 9
[Submit][Status][Discuss]

Description

自从上次神刀手帮助蚯蚓国增添了上千万人口(蚯口?),蚯蚓国发展得越来越繁荣了!最近,他们在地下发现了

一些神奇的纸张,经过仔细研究,居然是D国X市的超级计算机设计图纸!这台计算机叫做‘树状图’,由n个计算

节点与n1条可以双向通信的网线连接而成,所有计算节点用不超过n的正整数编号。顾名思义,这形成了一棵树的

结构。蚯蚓国王已在图纸上掌握了这棵树的完整信息,包括n的值与n1条网线的连接信息。于是蚯蚓国王决定,派

出蚯蚓国最强大的两个黑客,小P和小H,入侵‘‘树状图’’,尽可能地摧毁它。小P和小H精通世界上最好的编程

语言,经过一番商量后,他们决定依次采取如下的步骤:小P选择某个计算节点,作为他入侵的起始点,并在该节

点上添加一个P标记。重复以下操作若干次(可以是0次):–小P从他当前所在的计算节点出发,选择一条没有被

标记过的网线,入侵到该网线的另一端的计算节点,并在路过的网线与目的计算节点上均添加一个P标记。小H选择

某个计算节点,作为她入侵的起始点,并在该节点上添加一个H标记。重复以下操作若干次(可以是0次):–小H

从她当前所在的计算节点出发,选择一条没有被标记过的网线,入侵到该网线的另一端的计算节点,并在路过的网

线与目的计算节点上均添加一个H标记。(注意,小H不能经过带有P标记的网线,但是可以经过带有P标记的计算节

点)删除所有被标记过的计算节点和网线。对于剩下的每条网线,如果其一端或两端的计算节点在上一步被删除了

,则也删除这条网线。经过以上操作后,‘‘树状图’’会被断开,剩下若干个(可能是0个)连通块。为了达到

摧毁的目的,蚯蚓国王希望,连通块的个数越多越好。于是他找到了你,希望你能帮他计算这个最多的个数。小P

和小H非常心急,在你计算方案之前,他们可能就已经算好了最优方案或最优方案的一部分。你能得到一个值x:若

x=0,则说明小P和小H没有算好最优方案,你需要确定他们两个的入侵路线。若x=1,则说明小P已经算好了某种两

人合作的最优方案中,他的入侵路线。他将选择初始点p0,并沿着网线一路入侵到了目标点p1,并且他不会再沿着

网线入侵;你只需要确定小H的入侵路线。若x=2,则说明小P和小H算好了一种两人合作的最优方案,小P从点p0入

侵到了p1并停下,小H从点h0入侵到了h1并停下。此时你不需要指挥他们入侵了,只需要计算最后两步删除计算节

点与网线后,剩下的连通块个数即可。

Input

每个输入文件包含多个输入数据。输入文件的第一行为两个整数 T 和 x, T 表示

该文件包含的输入数据个数, x 的含义见上述。(同一个输入文件的所有数据的 x 都是相同的)

接下来依次输入每个数据。

每个数据的第一行有若干个整数:

若 x = 0,则该行只有一个整数 n。

若 x = 1,则该行依次有三个整数 n, p0, p1。

若 x = 2,则该行依次有五个整数 n, p0, p1, h0, h1。

保证 p0, p1, h0, h1 均为不超过 n 的正整数。

每个数据接下来有 n  1 行,每行有两个不超过 n 的正整数,表示这两个编号的计

算节点之间有一条网线将其相连。保证输入的是一棵树。

同一行相邻的整数之间用恰好一个空格隔开。

对于整数 k,设 ∑ n^k 为某个输入文件中,其 T 个输入数据的 n^k 之和。

所有输入文件满足 T ≤ 10^5, ∑ n^1 ≤ 5 × 10^5。

数据文件可能较大,请避免使用过慢的输入输出方法。

Output

对于每个数据,输出一行,表示在给定条件下,剩下连通块的最大个数。

在bzoj上听说标程T掉了,那我就无耻的骗一波访问量啦>_<

不妨把树上一条从上往下的路径看成一条线,那么每个点总共只有7种状态(值都为能形成最多的联通块个数),路径就指题面中的那两条路径

1.子树中没有任何路径 不用记录

2.子树中有一条路径,且不经过这个点 记为$f$

3.子树中有两条路径,且不经过这个点 记为$g$

4.这个点连着一个线头(经过这个点),且子树里只有一条路径 记为$h$

5.这个点连着两个线头,且子树里只有一条路径 记为$h1$

6.这个点连着一个或三个线头,且子树里有两条路径 记为$l$

7.这个点连着两个或四个线头,且子树里有两条路径 记为$l1$

其实67中的1.3 2.4 没有什么区别,重点只是能不能再伸出去一条线

转移太麻烦了概括的说一下

显然两个能伸出去的线头是可以合并的(编号大的状态可以由编号小的状态合并而来)

这个点的线头也可以由它某个儿子直接伸过来

我记录了一个num表示当前儿子节点之前有多少个儿子节点(即全选1状态)

mk表示在之前的儿子节点某一个选2或4或5,其他全选1的最大值。

然后就是细节 。。。细节。。。(不枉我省选调了4个小时)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 100005
using namespace std;
int read()
{
    int p=0;char c=getchar();
    while(c<‘0‘||c>‘9‘)c=getchar();
    while(c>=‘0‘&&c<=‘9‘)p=p*10+c-‘0‘,c=getchar();
    return p;
}
int cas,t,n;
int head[N],nxt[N*2],ver[N*2],tot;
void add(int a,int b)
{
    tot++;nxt[tot]=head[a];head[a]=tot;ver[tot]=b;return ;
}
int f[N],h[N],l[N],g[N],h1[N],l1[N];
int ans;
int mx(int a,int b)
{
    if(a>b)return a;
    return b;
}
void dfs(int x,int ff)
{
    int num=0,mk=0;
    for(int i=head[x];i;i=nxt[i])
    {
        if(ver[i]==ff)continue;
        dfs(ver[i],x);

        int tf=f[x],tg=g[x],th=h[x]+1,tl=l[x]+1,th1=h1[x]+1,tl1=l1[x]+1;

        tf=mx(tf,f[ver[i]]);
        tf=mx(tf,mx(h1[ver[i]],h[ver[i]])+1);

        tg=mx(tg,g[ver[i]]);
        tg=mx(tg,mx(l1[ver[i]],l[ver[i]])+1);
        tg=mx(tg,f[x]+mx(h1[ver[i]],h[ver[i]]));

        th=mx(th,h[ver[i]]+num);
        tl=mx(tl,l[ver[i]]+num);

        th1=mx(th1,h[x]+h[ver[i]]);

        tl=mx(tl,h[x]+f[ver[i]]);
        tl=mx(tl,h1[x]+h[ver[i]]);
        tl=mx(tl,h1[ver[i]]+h[x]);
        tl=mx(tl,h[ver[i]]+mk);

        tl1=mx(tl1,h1[ver[i]]+h1[x]);
        tl1=mx(tl1,l[x]+h[ver[i]]);
        tl1=mx(tl1,l[ver[i]]+h[x]);
        tl1=mx(tl1,h1[x]+f[ver[i]]);
        tl1=mx(tl1,h[ver[i]]+l[x]);

	    mk=max(mk+1,num+mx(h1[ver[i]],mx(h[ver[i]],f[ver[i]])));
        num++;
        f[x]=tf;g[x]=tg;h[x]=th;l[x]=tl;l1[x]=tl1;h1[x]=th1;

    }
    h[x]=max(h[x],num);
    return ;
}
int main()
{
    cas=read();t=read();
    int t1,t2,t3,t4;
    while(cas--)
    {
        if(!t)n=read();
        else if(t==1)n=read(),t1=read(),t2=read();
        else n=read(),t1=read(),t2=read(),t3=read(),t4=read();
            for(int i=1;i<n;i++)
            {
                t1=read();t2=read();
                add(t1,t2);add(t2,t1);
            }
            dfs(1,-1);
            printf("%d\n",mx(g[1],mx(l1[1],l[1])));
            tot=0;
            for(int i=1;i<=n;i++)head[i]=0;
            for(int i=1;i<=n;i++)h[i]=f[i]=l[i]=g[i]=l1[i]=h1[i]=0;
    }
    return 0;
}

  

时间: 2024-08-05 23:40:19

bzoj 4871: [Shoi2017]摧毁“树状图”的相关文章

bzoj 4871: [Shoi2017]摧毁“树状图”【树形dp】

做不来--参考https://www.cnblogs.com/ezyzy/p/6784872.html #include<iostream> #include<cstdio> using namespace std; const int N=100005; int T,o,n,h[N],cnt,f[N],g[N],q[N],q1[N],l[N],l1[N]; struct qwe { int ne,to; }e[N<<1]; int read() { int r=0,f

D3树状图给指定特性的边特别显示颜色

D3作为前端图形显示的利器,功能之强,对底层技术细节要求相对比较多. 有一点,就是要理解其基本的数据和节点的匹配规则架构,即enter,update和exit原理,我前面的D3基础篇中有介绍过,不明白的可以再去研究下. 本篇博文,同样是在这个框架下,完成修改树状图中某两个节点之间的边用红色线条连接,实现表达特殊含义的目的. 背景故事: 微信朋友圈之间产品帖子相互转发,有些帖子转发后会有成交,只要有成交,则这个促成成交的节点及其之上的父节点都相应是有功劳的,这个轨迹需要用高亮的颜色表示(比如本例中

Android开源图表之树状图和饼状图的官方示例的整理

最近由于工作需要,所以就在github上搜了下关于chart的三方框架 官方地址https://github.com/PhilJay/MPAndroidChart 由于工作需要我这里整理了一份Eclipse版本的类库.(有需要要的留下邮箱) 这就是Code中的效果(树状图) 1 public class BarChartActivity extends Activity implements OnChartValueSelectedListener{ 2 3 private BarChart m

【 D3.js 入门系列 --- 9.5 】 树状图的制作

这一节学习树状图的制作.树状图的制作和集群图完全相同,经过这两种 layout 转换后的数据也很相似. 本人的个人博客为: www.ourd3js.com csdn博客为: blog.csdn.net/lzhlzz 转载请注明出处,谢谢. 树状图( Tree )通常用于表示层级.上下级.包含与被包含关系.树状图的制作和 9.4节集群图的制作 的代码几乎完全一样.不错,你没看错,几乎完全一样.那么为什么要把这两种图分开,它们有什么不同呢?先来看看对于同一组数据,它们的结果有什么不同.数据为: {

一款很好用的JQuery dtree树状图插件

一款很好用的JQuery dtree树状图插件 树状图  -dtree 由于他的节点设置思想不错,使连接数据库的数据库设计比较方便. 下载dtree资源包,引用一下dtree.css和dtree.js文件,然后编写节点就行了. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quo

Linux命令之pstree - 以树状图显示进程间的关系

本文链接:http://codingstandards.iteye.com/blog/842156   (转载请注明出处) 用途说明 pstree命令以树状图显示进程间的关系(display a tree of processes).ps命令可以显示当前正在运行的那些进程的信息,但是对于它们之间的关系却显示得不够清晰.在Linux系统中,系统调用fork可以创建子进程,通过子shell也可以创建子进程,Linux系统中进程之间的关系天生就是一棵树,树的根就是进程PID为1的init进程. 常用参

D3树状图异步按需加载数据

D3.js这个绘图工具,功能强大不必多说,完全一个Data Driven Document的绘图工具,用户可以按照自己的数据以及希望实现的图形,随心所欲的绘图. 图形绘制,D3默认采用的是异步加载,但是,这里的异步加载,指的是一次性的将图形展示所需要的数据异步的方式加载到浏览器前端显示.主要有如下这两种方式: 1 d3.csv(url[[, row], callback]) 2 3 Creates a request for the CSV file at the specified url w

[Linux] Linux命令之pstree - 以树状图显示进程间的关系

转载自: http://codingstandards.iteye.com/blog/842156 pstree命令以树状图显示进程间的关系(display a tree of processes).ps命令可以显示当前正在运行的那些进程的信息,但是对于它们之间的关系却显示得不够清晰.在Linux系统中,系统调用fork可以创建子进程,通过子shell也可以创建子进程,Linux系统中进程之间的关系天生就是一棵树,树的根就是进程PID为1的init进程. 常用参数 格式:pstree 以树状图显

ArcGIS教程:树状图

摘要 构造可显示特征文件中连续合并类之间的属性距离的树示意图(树状图). 用法 · 输入特征文件必须采用预定的特征文件格式.特征文件可使用 Iso 聚类或创建特征工具来创建.该文件必须至少包含两个类.可通过扩展名 .gsg 来识别特征文件. · 树状图的输出是一个 ASCII 文本文件.该文件包含两部分:表和图形. 第一部分是以合并顺序显示各类对之间距离的表.第二部分是使用类的 ASCII 字符的图形表达,用来演示合并关系和等级.图形说明了特征文件中合并类对之间的相对距离,这些距离均基于统计得到