Codeforces 398C Tree and Array 构造

题目大意:

就是现在要构造一个有N个节点的树(5 <= n <= 10^5), 然后树上的点的编号是1到n, 每当将树上的点(u, v)连接出一条边的时候, 设置权值为c, 则将数组T的第u到v项都加上c, (u < v)

然后如果数对 (u, v)满足树上u和v两个点的最短距离和∑T[i] (u <= i <= v)相等, 则称(u, v)是一个good pair (u < v), 树上的权值必须是正整数

现在给出N, 要求构造一颗树使得good pair不少于n / 2向下取整

输出构造的树的N - 1条边及其权值, 以及n/2向下取整个good pair

如果答案有多种输出任意一种即可


代码如下:

Result  :  Accepted     Memory  :  4 KB     Time  :  62 ms

/*
 * Author: Gatevin
 * Created Time:  2015/3/3 16:08:44
 * File Name: Shana.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;

/*
 * 首先我们考虑n是偶数的情况(n >= 6)
 * 将点分为两组一组是(1, 2, 3, ... n / 2), 另一组是(n/2 + 1, n/2 + 2, ... n)
 * 首先连接边(1, n/2 + 1) (2, n/2 + 2).. (n/2, n)且边权值都设为1
 * 那么t数组就变成了[1, 2, 3, 4, ... n/2, n/2, n/2 - 1, ... 2, 1]
 * 接下来连接(n/2 + 1, n/2 + 2)边权值设为1, 可以发现(1, 2)距离是3且t[1] + t[2] == 3
 * 接下来将(n/2 + 2, n/2 + 3) (n/2 + 3, n/2 + 4) ... (n/2 + n/2 - 1, n/2 + n/2)
 * 边权值依次设为3, 4, 5, 6,...n/2
 * 可以发现此时(1, 2) (1, 3) (1, 4) ... (1, n/2)都满足条件, 并且(2, 3)也满足条件
 * 所以对于偶数个点(n >= 6)此构造有效
 * 对于n为奇数且n >= 7而言, 分组为(1, 2, 3, ... n/2) (n/2 + 1, n/2 + 2,...,n - 1) (n)即可
 * 前面两组构造好之后把n和n - 1连接起来, 实际上也一样
 * 最后就是n == 5的情况较特殊= =, 我的这个构造方法不适用
 * 所以n == 5需要特殊讨论自己构造一个...不过我画了半天没画出来...还是参考了作者的画法..
 */

int n;

int main()
{
    scanf("%d", &n);
    if(n == 5)//n == 5的情况特殊讨论, 因为按照之前的构造法(1, 2)之后没有(1, 3)存在也没有(2, 3)存在
    {
        printf("1 2 3\n");//这个n == 5的解释参考作者的...自己没构造出来= =
        printf("1 3 3\n");
        printf("2 4 2\n");
        printf("4 5 1\n");
        printf("3 4\n");
        printf("3 5\n");
        return 0;
    }
    for(int i = 1; i <= (n >> 1); i++)
        printf("%d %d %d\n", i, (n >> 1) + i, 1);
    printf("%d %d %d\n", (n >> 1) + 1, (n >> 1) + 2, 1);
    for(int i = (n >> 1) + 2; i < n; i++)
        printf("%d %d %d\n", i, i + 1, i - (n >> 1) + 1);
    for(int i = 2; i <= (n >> 1); i++)
        printf("1 %d\n", i);
    printf("2 3\n");
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值