HDU 5682:zxa and leaf 二分

zxa and leaf

 
 Accepts: 25
 
 Submissions: 249
 Time Limit: 5000/2500 MS (Java/Others)
 
 Memory Limit: 65536/65536 K (Java/Others)
问题描述
zxa有一棵含有nn个节点的无根树,包含(n-1)(n1)条无向边,点从11nn编号,定义每个点的度数为与这个点相连的边的数量,度数为11的节点被称作这棵树的叶子节点。

zxa想给每个节点设置它的好看度,好看度必须为正整数。他的无根树有m(1\leq m\leq n)m(1mn)个叶子节点,其中的k(1\leq k\leq m)k(1km)个叶子节点的好看度已经确定,zxa只需要设置其他节点的好看度。

zxa很好奇,如果令每条边的难看度是这条边所连接的两个节点的好看度差值的绝对值,整棵树的难看度是所有边的难看度中的最大值,那么这棵树的难看度最小是多少,你能帮助他吗?
输入描述
第一行有一个正整数TT,表示有TT组数据。

对于每组数据:

第一行有两个正整数nnkk,表示这棵树有nn个节点,其中kk个叶子节点的好看度已经确定。

接下来(n-1)(n1)行,每行有两个互异的正整数uuvv,表示节点uu和节点vv之间有一条无向边。

接下来kk行,每行有两个正整数uuww,表示节点uu是叶子节点,而且它的好看度是ww。

每一行相邻数字之间只有一个空格。

保证输入的边构成一棵树。

1\leq T\leq 10,2\leq n\leq 5\cdot10^4,1\leq k\leq n,1\leq u,v\leq n,1\leq w\leq 10^91T10,2n5104,1kn,1u,vn,1w109
输出描述
对于每组数据,输出一行,包含一个非负整数,表示这棵树的难看度最小值。
输入样例
2
3 2
1 2
1 3
2 4
3 9
6 2
1 2
1 3
1 4
2 5
2 6
3 6
5 9
输出样例
3
1
Hint
如果你需要更大的栈空间,请使用#pragma comment(linker, "/STACK:102400000,102400000")并且选择使用C++提交你的代码。
这个题其实考虑到二分,也就可以出了,每个点有自己的一个取值区间,然后如果这个mid能够满足所有点的取值区间,就ok。

所以总结一下这个题,一开始没思路,是因为二分根本抓瞎,太弱没想到。后来RE,是因为没有考虑到两个点的情况,两个点的话都是叶子节点了,这种情形要考虑到。最后wa的原因是在INF,要设置成1e9就够了,之前设置的太大,导致爆了int。

代码:

#pragma comment(linker, "/STACK:102400000,102400000") 
#pragma warning(disable:4996)
#include <fstream>
#include <iostream>
#include <functional>
#include <algorithm>
#include <cstring>
#include <vector>
#include <string>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <deque>
#include <set>
#include <map>
using namespace std;
typedef long long ll;

#define INF 1e9 + 1
#define mem(a, b) memset(a, b, sizeof(a))
#define pper(i,n,m) for(int i = n;i >= m; i--)
#define repp(i, n, m) for (int i = n; i <= m; i++)
#define rep(i, n, m) for (int i = n; i < m; i++)
#define sa(n) scanf("%d", &(n))
#define mp make_pair
#define ff first
#define ss second
#define pb push_back

const int maxn = 1e5 + 5;
const ll mod = 1e9 + 7;
const double PI = acos(-1.0);

struct ed
{
    int to;
    int next;
}edge[maxn * 2];

int n, k, f, edgen, mid;
int head[maxn], vis[maxn], leaf[maxn], val[maxn], out[maxn];

pair<int, int>dfs(int x)
{
    if (f == 0)
        return mp(0, 0);
    vis[x] = 1;

    int i, j;
    int ri = INF, le = -INF;
    if (leaf[x] == 1)
    {
        le = ri = val[x];
    }
    for (i = head[x]; i != -1; i = edge[i].next)
    {
        int to = edge[i].to;
        if (vis[to] == 0)
        {
            pair<int, int>s = dfs(to);
            if (s.ff == -INF)
                continue;
            le = max(le, s.ff - mid);
            ri = min(ri, s.ss + mid);
            if (le > ri)
            {
                f = 0;
                return mp(0, 0);
            }
        }
    }

    return mp(le, ri);
}

void init()
{
    edgen = 0;
    memset(head, -1, sizeof(head));
    memset(edge, -1, sizeof(edge));
    memset(leaf, 0, sizeof(leaf));
    memset(val, 0, sizeof(val));
    memset(out, 0, sizeof(out));
}

void addedge(int u, int v)
{
    edgen++;
    edge[edgen].to = v;
    edge[edgen].next = head[u];
    head[u] = edgen;
}

void solve()
{
    int i, j;
    int u, v;
    sa(n), sa(k);
    repp(i, 1, n - 1)
    {
        sa(u), sa(v);
        addedge(u, v);
        addedge(v, u);
        out[u]++;
        out[v]++;
    }
    repp(i, 1, k)
    {
        sa(u), sa(v);
        leaf[u] = 1;
        val[u] = v;
    }
    int root, le, ri;
    if (n == 2)
    {
        root = 1;
    }
    else
    {
        repp(i, 1, n)
        {
            if (out[i] > 1)
            {
                root = i;
                break;
            }
        }
    }
    ri = INF, le = 0;
    while (le < ri)
    {
        mid = (ri + le) / 2;
        f = 1;
        memset(vis, 0, sizeof(vis));
        dfs(root);
        if (f)
        {
            ri = mid;
        }
        else
        {
            le = mid + 1;
        }
    }
    printf("%d\n", ri);
}

int main()
{
#ifndef ONLINE_JUDGE  
    freopen("i.txt", "r", stdin);
    freopen("o.txt", "w", stdout);
#endif

    int t;
    sa(t);
    while (t--)
    {
        init();
        solve();
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值