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)条无向边,点从11到nn编号,定义每个点的度数为与这个点相连的边的数量,度数为11的节点被称作这棵树的叶子节点。

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

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

对于每组数据:

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

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

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

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

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

1leq Tleq 10,2leq nleq 5cdot10^4,1leq kleq n,1leq u,vleq n,1leq wleq 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

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <map>
#include <queue>
#include <cstring>
using namespace std;
const int Max=5e4+10;
typedef long long LL;
vector<int>book[Max];
const int inf=1e9+10;
int vis1[Max],a[Max],vis2[Max];
int pnt[Max*2],head[Max],nxt[Max*2],e; //如果边数写错给小了,报超时什么鬼。。。
inline void addedge(int u,int v)
{
    pnt[e]=v;nxt[e]=head[u];head[u]=e++;
}
int maxx[Max],minx[Max],limit;
bool dfs(int u)
{
    int v;
    maxx[u]=inf;minx[u]=0;  //每个虚节点节点范围设为无限大
    if(vis1[u]) maxx[u]=minx[u]=a[u];
    for(int i=head[u];i!=-1;i=nxt[i])
    {
        v=pnt[i];
        if(!vis2[v])
        {
           vis2[v]=1;
           if(!dfs(v)) return 0;     //先dfs,使得所有的节点都有范围
           vis2[v]=0;
           maxx[u]=min(maxx[u],maxx[v]+limit);
           minx[u]=max(minx[u],minx[v]-limit); //每一个节点的范围需要满足相邻节点的要求
        }
    }
    return maxx[u]>=minx[u]; //每一个节点都必须满足条件
}
bool check(int len)
{
    limit=len;
    memset(vis2,0,sizeof(vis2));
    if(!dfs(1)) return 0;
    return 1;
}
int main()
{
    int T;
    for(scanf("%d",&T);T;T--)
    {
        memset(head,-1,sizeof(head));
        memset(nxt,-1,sizeof(nxt));
        memset(pnt,-1,sizeof(pnt));
        memset(vis1,0,sizeof(vis1));
        int n,k,u,v;
        scanf("%d%d",&n,&k);
        e=0;
        for(int i=1;i<=n-1;i++)
        {
            scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
        for(int i=1;i<=k;i++)
        {
            scanf("%d%d",&u,&v);
            a[u]=v;
            vis1[u]=1;
        }
        int l=0,r=inf,ans,mid;  //二分求得答案
        while(l<=r)        
        {
            mid=(l+r)>>1;
            if(check(mid)) r=mid-1,ans=mid;
            else           l=mid+1;
        }
        printf("%d
",ans);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/zsyacm666666/p/5671708.html