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

44 篇文章 0 订阅

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

Time Limit: 25 Sec Memory Limit: 512 MB
Submit: 133 Solved: 45
[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

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

1 0

13

1 2

2 3

2 4

4 5

4 6

4 7

7 8

7 9

9 10

10 11

10 12

12 13

Sample Output

8

这个输入文件只有一个输入数据。一种最优的方案如下:

小 P 从节点 2 开始入侵,节点 2 被小 P 标记。

小 P 从节点 2 入侵到节点 4,节点 4 和经过的网线被小 P 标记。

小 P 从节点 4 入侵到节点 7,节点 7 和经过的网线被小 P 标记。

小 H 从节点 10 开始入侵,节点 10 被小 H 标记。

删除被标记的节点 2,4,7,10 和被标记的网线 (2,4) 和 (4,7)。

删除任意一端在上一步被删除的网线。

此时还剩下 8 个连通块。其中节点 1,3,5,6,8,9,11 各自形成一个连通块,节点 12,13

形成了一个连通块。
HINT

2017.4.28新加数据一组By 150137

Source

黑吉辽沪冀晋六省联考

[Submit][Status][Discuss]


考虑所有答案可能的情况
若两路径不相交:
1. 两路径顶点的 LCA 不是两路径的顶点
2. 两路径顶点的 LCA 是其中一条的顶点

若两路径相交,则交集肯定是一个单独的点
枚举交集延伸出去的链的条数,必定不超过四

然后对于每个节点,维护一下几种图形
这里写图片描述
0:经过当前根的一条链
1:子树中的一条路径
2:经过当前根的一条路径
3:过当前根类似”三叉戟”的图型
4:过当前根的一条链已经子树总的一条路径,不相交
显然各种答案是可以通过它们拼出来的

转移嘛。。。。。。。手动推吧
真的一点都不麻烦!!!

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define max(a,b) ((a) > (b) ? (a) : (b))
using namespace std;

const int maxn = 5E5 + 5;

int T,G,GG,n,Ans,I,f[maxn][5];

vector <int> v[maxn];

inline int getint()
{
    char ch = getchar(); int ret = 0;
    while (ch < '0' || '9' < ch) ch = getchar();
    while ('0' <= ch && ch <= '9')
        ret = ret * 10 + ch - '0',ch = getchar();
    return ret;
}

inline void Dfs(int x,int from)
{
    int fg = x == 1 ? 0 : 1,sz = v[x].size();
    int fr,sc,ti,fu,m1,m2,mx,pf,ps;
    fr = sc = ti = fu = m1 = m2 = mx = pf = ps = 0;
    for (int i = 0; i < sz; i++)
    {
        int to = v[x][i];
        if (to == from) continue; Dfs(to,x);
        f[x][0] = max(f[x][0],f[to][0] + sz - fg - 1);
        f[x][1] = max(f[x][1],max(f[to][2],f[to][1]));
        f[x][3] = max(f[x][3],f[to][3] + sz - fg - 1);
        f[x][4] = max(f[x][4],f[to][4] + sz - fg - 1);
        f[x][4] = max(f[x][4],f[to][1] + sz - fg);
        f[x][4] = max(f[x][4],f[to][1] + sz - fg - 1 + fr);
        f[x][4] = max(f[x][4],f[to][2] + sz - fg - 1);
        f[x][4] = max(f[x][4],f[to][2] + sz + fr - fg - 2);
        f[x][4] = max(f[x][4],f[to][0] + mx + sz - fg - 1);
        if (f[to][0] >= fr)
        {
            fu = ti; ti = sc; sc = fr;
            ps = pf; fr = f[to][0]; pf = to;
        }
        else if (f[to][0] >= sc)
            fu = ti,ti = sc,sc = f[to][0],ps = to;
        else if (f[to][0] >= ti) fu = ti,ti = f[to][0];
        else fu = max(fu,f[to][0]);
        int tmp = max(f[to][1],f[to][2]);
        if (tmp >= m1) m2 = m1,m1 = tmp;
        else m2 = max(m2,tmp);
        mx = max(mx,max(f[to][1],f[to][2] - 1));
    }
    f[x][0] = max(f[x][0],sz - fg);
    Ans = max(Ans,m1 + m2 + 1); f[x][2] = f[x][0];
    f[x][2] = max(f[x][2],fr + sc + sz - fg - 2);
    f[x][3] = max(f[x][3],max(f[x][0],f[x][2]));
    f[x][3] = max(f[x][3],fr + sc + ti + sz - fg - 3);
    Ans = max(Ans,f[x][0] + fg);
    Ans = max(Ans,f[x][2] + fg);
    Ans = max(Ans,f[x][3] + fg);
    Ans = max(Ans,fr + sc + ti + fu + sz - 4);
    for (int i = 0; i < sz; i++)
    {
        int to = v[x][i],One,Two;
        if (to == from) continue;
        if (to == pf) One = sc,Two = sc + ti;
        else if (to == ps) One = fr,Two = fr + ti;
        else One = fr,Two = fr + sc;
        Ans = max(Ans,f[to][1] + sz);
        Ans = max(Ans,f[to][1] + One + sz - 1);
        Ans = max(Ans,f[to][1] + Two + sz - 2);
        Ans = max(Ans,f[to][2] + One + sz - 2);
        Ans = max(Ans,f[to][2] + Two + sz - 3);
        Ans = max(Ans,f[to][3] + sz - 1);
        Ans = max(Ans,f[to][3] + One + sz - 2);
        Ans = max(Ans,f[to][4] + sz - 1);
        Ans = max(Ans,f[to][4] + One + sz - 2);
    }
}

inline void Clear()
{
    Ans = 0;
    for (int i = 1; i <= n; i++)
        memset(f[i],0,sizeof(f[i])),v[i].clear();
}

inline void Solve()
{
    n = getint();
    for (int i = 0; i < G; i++) GG = getint();
    for (int i = 1; i < n; i++)
    {
        int x = getint(),y = getint();
        v[x].push_back(y); v[y].push_back(x);
    }
    if (n == 1) {puts("0"); return;}
    Dfs(1,0); printf("%d\n",Ans);
}

int main()
{
    #ifdef DMC
        freopen("DMC.txt","r",stdin);
        freopen("test.txt","w",stdout);
    #endif

    T = getint(); G = getint() << 1;
    while (T--) Solve(),Clear();
    //for (I = 1; I <= 5; I++) Solve(),Clear();
    //for (I = 6; I <= T; I++) Solve(),Clear();
    return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值