HDU 5682
1 /* 2 http://acm.hdu.edu.cn/showproblem.php?pid=5682 3 题意:http://bestcoder.hdu.edu.cn/contests/contest_chineseproblem.php?cid=696&pid=1003 4 思路:每个节点存储满足的值域,在[0,1e9]上二分查找最小丑陋值,然后每个点的值域通过子节点值域得出; 5 值域要是有矛盾就往大了找,要是符合就往小了找; 6 2017年02月26日17:14:12 7 */ 8 #include <cstdio> 9 #include <vector> 10 #include <cstring> 11 #include <algorithm> 12 using namespace std; 13 #define N 50010 14 //存储节点值域,int可能会有问题 15 long long lv[N]; 16 long long rv[N]; 17 //存储叶节点的美丽值 18 long long caotama[N]; 19 //存储每个节点的爸爸节点,然后不搜索这个爸爸节点 20 int baba[N]; 21 //是否是叶节点 22 bool notleaf[N]; 23 //边表 24 int v[N*2];//边终点 25 int pre[N*2];//前一个同起点边 26 int last[N];//i点为起点最后一条边 27 //当前要验证的值 28 int m; 29 bool dfs(int id){ 30 if(notleaf[id]){//这里每次重新验证的时候要把不是叶节点的更新成一个足够大的范围 31 lv[id]=-1e14; 32 rv[id]=1e14; 33 }else{//他妈的1是叶节点的话,从1搜会把1的范围改变,妈的,要把1的范围还原了 34 lv[id]=caotama[id]; 35 rv[id]=caotama[id]; 36 } 37 int now=last[id]; 38 while(now){ 39 if(v[now]!=baba[id]){//爸爸节点不用搜了 40 baba[v[now]]=id;//子节点的爸爸节点就是现在这个节点 41 if(dfs(v[now])){ 42 lv[id]=max(lv[id],lv[v[now]]-m); 43 rv[id]=min(rv[id],rv[v[now]]+m); 44 if(rv[id]<lv[id]){ 45 return false; 46 } 47 }else{ 48 return false; 49 } 50 } 51 now=pre[now]; 52 } 53 return true; 54 } 55 int ef(int l,int r){ 56 if(l==r)return l; 57 m=(l+r)/2; 58 if(dfs(1)){//成功了就往小的找 59 return ef(l,m); 60 }else{//没成功就往大了找 61 return ef(m+1,r); 62 } 63 } 64 int main(){ 65 int t; 66 scanf("%d",&t); 67 while(t--){ 68 memset(notleaf,true,sizeof(notleaf)); 69 memset(last,0,sizeof(last)); 70 memset(baba,0,sizeof(0)); 71 int n,k; 72 scanf("%d %d",&n,&k); 73 int tmpa,tmpb; 74 for(int i=1;i<n;i++){ 75 scanf("%d %d",&tmpa,&tmpb); 76 v[i<<1]=tmpb; 77 pre[i<<1]=last[tmpa]; 78 last[tmpa]=i<<1; 79 v[i<<1|1]=tmpa; 80 pre[i<<1|1]=last[tmpb]; 81 last[tmpb]=i<<1|1; 82 } 83 for(int i=0;i<k;i++){ 84 scanf("%d %d",&tmpa,&tmpb); 85 caotama[tmpa]=tmpb; 86 notleaf[tmpa]=false; 87 } 88 printf("%d\n",ef(0,1e9)); 89 } 90 return 0; 91 }