bzoj 2799 [Poi2012]Salaries 性质+二分

题目大意

给出一棵n个结点的有根树,结点用正整数1~n编号。
每个结点有一个1~n的正整数权值,不同结点的权值不相同,
并且一个结点的权值一定比它父结点的权值小(根结点的权值最大,一定是n)。
现在有些结点的权值是已知的,并且如果一个结点的权值已知,它父结点的权值也一定已知。
问还有哪些结点的权值能够唯一确定。
最后输出每个点的全值,不知道输出0
n<=1,000,000

分析

我们求出每个点最大可以是什么权值
如果i点权值<=d,而<=d中的权值已经确定了d-1个,那么i的权值也可以确定
按照贪心,我们从小到大填权值

做法

求每个点最大权值就dfs+二分
后面选数就按权值从小到大扫就可以了

solution
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <algorithm>
using namespace std;
const int M=1000007;
 
inline int rd(){
    int x=0;bool f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
    for(;isdigit(c);c=getchar()) x=x*10+c-48;
    return f?x:-x;
}
 
int n,rt;
int g[M],te;
struct edge{int y,next;}e[M];
int vis[M];
int val[M];
int pre[M];
int a[M],tot;
 
struct node{
    int d,id;
    node (int dd=0,int ii=0){d=dd;id=ii;}
}b[M];
int num;
 
bool cmp(node x,node y){return x.d<y.d;}
 
void addedge(int x,int y){
    e[++te].y=y;e[te].next=g[x];g[x]=te;
}
 
int find(int d){
    int l=1,r=tot,mid;
    while(l<r){
        int mid=(l+r)/2+1;
        if(a[mid]>=d) r=mid-1;
        else l=mid;
    }
    return a[l];
}
 
void dfs(int x,int mx){
    if(val[x]) mx=val[x];
    else {
        mx=find(mx);
        b[++num]=node(mx,x);
    }
    int p,y;
    for(p=g[x];p;p=e[p].next)
    if((y=e[p].y)!=pre[x]){
        dfs(y,mx);
    }
}
 
int main(){
    int i,j,x,y,z;
    n=rd();
    for(i=1;i<=n;i++){
        y=rd(),z=rd();
        if(i==y) rt=i;
        else pre[i]=y,addedge(y,i);
        val[i]=z;
        vis[z]=1;
    }
     
    for(i=1;i<=n;i++)
        if(!vis[i]) a[++tot]=i;
     
    dfs(rt,n);
     
    sort(b+1,b+num+1,cmp);
     
    int cnt=0;
    j=1;
    for(i=1;i<=n;i++){
        if(vis[i]){
            cnt++;
            continue;
        }
        if(b[j].d==i){
            int tp=j;
            for(;j<=num&&b[j].d==i;j++);
            if(cnt==i-1) val[b[j-1].id]=i;
            cnt+=j-tp;
        }
    }
     
    for(i=1;i<=n;i++) printf("%d\n",val[i]);
     
    return 0;
}

转载于:https://www.cnblogs.com/acha/p/6407320.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值