计蒜客 微软的员工福利

4 篇文章 0 订阅
2 篇文章 0 订阅

n 个点的树,每个点的权值可为ri pi ,定义 fi=xi/1000666i ,其中, xi 是第 i 个点及其所有儿子权值的极差。求maxfi
尺取+贪心+树形dp

#include<cstring>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
const int inf=0x7fffffff;
const int M=100005;
typedef long long ll;
struct Edge{
    int to,nxt;
}edge[M<<1];
int last[M],allc;
int n;
void ins(int u,int v){
    edge[++allc]=(Edge){v,last[u]};last[u]=allc;
}
int dat[M][2];
ll dp[M][2];
bool cmp(int x,int y){
    return dat[x][1]<dat[y][1];
}
struct node{
    int id,val;
    long long ans;
    bool operator<(const node&a)const{
        return val<a.val;
    }
}num[M<<1];
int tot;
int cnt[M];
ll res[M];
ll ans,ans1,ans0;
void solve(int x,int K){
    ans=0;
    int sum=tot>>1;//必须同时满足sum个不同id决策存在 
    int mx,top=0;
    for(int i=0;i<tot;i++)
        cnt[num[i].id]=0;
    for(int id,i=0;i<tot;i++){
        //枚举最小值
        mx=num[i].val+K*1000;
        while(top<tot){
            if(num[top].val<=mx){
                id=num[top].id;
                cnt[id]++;
                if(cnt[id]==1){
                    res[id]=num[top].ans;
                    ans+=res[id];
                    sum--;//该id的决策存在 
                }
                if(cnt[id]==2){
                    ans-=res[id];// 
                    res[id]=max(dp[id][0],dp[id][1]);
                    ans+=res[id];
                }
                top++;
            }
            else break;
        }
        if(!sum){//所有决策均已满足
            if(dat[x][0]>=num[i].val)
                ans0=max(ans+dat[x][0]-1ll*K*666*x,ans0);
            if(dat[x][1]<=mx)
                ans1=max(ans+dat[x][1]-1ll*K*666*x,ans1);
        }
        id=num[i].id;
        cnt[id]--;
        if(cnt[id]==0){
            ans-=res[id];
            sum++;
        }
        if(cnt[id]==1){
            ans-=res[id];
            res[id]=dp[id][1];
            ans+=res[id];
        }
    }
}
void dfs(int x,int f){
    for(int i=last[x];i;i=edge[i].nxt){
        int y=edge[i].to;
        if(y==f)continue;
        dfs(y,x);
    }
    tot=0;
    for(int i=last[x];i;i=edge[i].nxt){
        int y=edge[i].to;
        if(y==f)continue;
        for(int j=0;j<2;j++)
            num[tot++]=(node){y,dat[y][j],dp[y][j]};
    }
    if(!tot){
        for(int j=0;j<2;j++)
            dp[x][j]=dat[x][j];
        return;
    }
    for(int j=0;j<2;j++)
        num[tot++]=(node){x,dat[x][j],0};
    sort(num,num+tot);
    ans1=ans0=-1ll*inf*inf;
    dp[x][0]=dp[x][1]=0;
    for(int i=0;i<101;i++)solve(x,i);
    dp[x][0]=ans0;
    dp[x][1]=ans1;
    return;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        for(int j=0;j<2;j++)
            scanf("%d",&dat[i][j]);
        if(dat[i][0]>dat[i][1])swap(dat[i][0],dat[i][1]);
    }
    for(int u,v,i=1;i<n;i++){
        scanf("%d%d",&u,&v);
        ins(u,v);ins(v,u);
    }
    dfs(1,0);
    printf("%lld\n",max(dp[1][0],dp[1][1]));
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值