zoukankan      html  css  js  c++  java
  • 【BZOJ2799】[Poi2012]Salaries 乱搞

    【BZOJ2799】[Poi2012]Salaries

    Description

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

    Input

    第一行一个正整数n (n<=1,000,000),表示树的结点数。
    下面共n行,第i行描述编号为i的结点,每行两个整数pi,zi (1<=pi<=n, 0<=zi<=n)。
    pi表示结点i的父结点,如果i=pi,说明i是根结点。
    当zi>0时,表示结点i的权值已知,并且就是zi;当zi=0时,表示结点i的权值未知。
    测试数据保证满足题意,并且存在合法的方案。

    Output

    输出共n行,依次描述每个结点。如果结点i的权值能够唯一确定,第i行输出结点i的权值,否则第i行输出0。

    Sample Input

    10
    2 2
    2 10
    1 0
    2 9
    2 5
    4 0
    6 0
    6 0
    5 0
    5 0

    Sample Output

    2
    2
    10
    1
    9
    5
    8
    0
    0
    0
    0

    题解:这题做法好神啊。。

    一个点的权值唯一确定等价于x>=val且x<=val,那么怎么求最大值呢?如果它父亲的最大值为val,那么从val-1往下找,找到第一个没有被占用的权值就是当前点的最大值。然后怎么求最小值呢?

    我们将所有点按最大值排序,然后从小往大一个一个确定每个点。如果有多个点的最大值=i,那么这些点都无法被确定。如果只有一个点的最大值=i,并且以前已经确定<=i-1的数有i-1个,那么这个点可以被唯一确定。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    const int maxn=1000010;
    int n,rt,cnt,sum,tot;
    int fa[maxn],to[maxn],next[maxn],head[maxn],v[maxn],ch[maxn],mx[maxn];
    struct node
    {
    	int mx,org;
    }s[maxn];
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    inline void add(int a,int b)
    {
    	to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
    }
    void dfs(int x,int mxx)
    {
    	if(!v[x])	s[++tot].mx=mxx,s[tot].org=x;
    	for(int i=head[x];i!=-1;i=next[i])
    	{
    		if(!v[to[i]])	dfs(to[i],mx[mxx-1]);
    		else	dfs(to[i],v[to[i]]);
    	}
    }
    bool cmp(const node &a,const node &b)
    {
    	return a.mx<b.mx;
    }
    int main()
    {
    	n=rd();
    	int i,j,tmp;
    	memset(head,-1,sizeof(head));
    	for(i=1;i<=n;i++)	mx[i]=i;
    	for(i=1;i<=n;i++)
    	{
    		fa[i]=rd(),v[i]=rd(),mx[v[i]]=0;
    		if(fa[i]==i)	rt=i,fa[i]=0;
    		else	add(fa[i],i);
    	}
    	for(i=1;i<=n;i++)	if(!mx[i])	mx[i]=mx[i-1];
    	dfs(rt,n);
    	sort(s+1,s+tot+1,cmp);
    	for(i=j=1;i<=n;i++)
    	{
    		if(mx[i]!=i)	sum++;
    		else
    		{
    			tmp=0;
    			for(;j<=tot&&s[j].mx==i;j++,tmp++);
    			if(tmp==1&&sum==i-1)	v[s[j-1].org]=i;
    			sum+=tmp;
    		}
    	}
    	for(i=1;i<=n;i++)	printf("%d
    ",v[i]);
    	return 0;
    }
  • 相关阅读:
    poj 3068 Bridge Across Islands
    XidianOJ 1086 Flappy v8
    XidianOJ 1036 分配宝藏
    XidianOJ 1090 爬树的V8
    XidianOJ 1088 AK后的V8
    XidianOJ 1062 Black King Bar
    XidianOJ 1091 看Dota视频的V8
    XidianOJ 1098 突击数论前的xry111
    XidianOJ 1019 自然数的秘密
    XidianOJ 1109 Too Naive
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7559911.html
Copyright © 2011-2022 走看看