hdu 5682

36 篇文章 0 订阅
12 篇文章 0 订阅

注意不能只是判断根节点的minn,maxx值大小,而是要判断所有节点的该值大小,有一个不合法就得返回是0,否则就wrong,也就是中间那句if(!dfs()) 特别重要!
正着反着都要去想一想

#include<iostream>
#include<cstdio>
#include<string.h>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std;
#define ll long long 
#pragma comment(linker, "/STACK:102400000,102400000") 
const int maxn=5e4+10;
int t,n,k,u,v;
vector<int>a[maxn];
int degree[maxn];int op[maxn];
int minn[maxn],maxx[maxn],vis[maxn];
int dfs(int u,int val){
    minn[u]=-(int)1e9;maxx[u]=(int)1e9;
    if(op[u]){
        minn[u]=op[u];maxx[u]=op[u];
    }
    for(int i = 0; i < a[u].size(); i++){
        int v = a[u][i];if(vis[v]) continue;
        vis[v] = 1;
    //    cout<<" u = "<<u<<" v = "<<v<<endl;
        if(!dfs(v,val)) return 0 ;
        maxx[u] = min(maxx[u] , maxx[v] + val);
        minn[u] = max(minn[u], minn[v] - val);
    }  
//    if(val == 3 && u == 1){
    //    cout<<" u = "<<u<<" maxx = "<<maxx[u]<<" minn = "<<minn[u]<<endl;
//    }
    return maxx[u] >= minn[u];
}
int main(){
    cin>>t;
    while(t--){
        //memset(degree,0,sizeof(degree));
        scanf("%d%d",&n,&k);
        for(int i = 1;i <= n;i ++) {
            a[i].clear();op[i] = 0 ;degree[i] = 0;
        }
        for(int i = 1 ;i <= n - 1 ;i ++){
            scanf("%d %d",&u,&v);
            a[u].push_back(v);a[v].push_back(u);
            degree[u]++;degree[v]++;
        }
        for(int i = 1; i <= k;i ++){
            scanf("%d%d",&u,&v);
            op[u] = v;
        }
        if(n == 2){
            cout<<abs(op[1]-op[2])<<endl;continue;
        }
        int root = 0;
        for(int i = 1;i <= n;i ++){
            if(degree[i] != 1){
                root = i;break;
            }
        }
    //    cout<<" root= "<<root <<endl;
    //    vis[root] = 1;
    //    puts("niin");
        int l = -1 ; int r = (int)1e9+1;
    //    cout<<" r= "<<r<<endl;
        while(l + 1 < r ){
            int mid = (l + r) / 2;
            memset(vis,0,sizeof(vis));
            vis[root] = 1;
        //    cout<<"root = "<<root<<endl;
        //    cout<<" mid = "<<mid<<endl;
            //memset(maxx,0,sizeof(maxx));
            if(dfs(root ,mid )){
                r = mid ;//cout<<"bingo"<<endl;
            }

            else l = mid ;
        //    system("pause");
        }
        printf("%d\n",r);
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值