• 【JZOJ5456】奇怪的队列【线段树】


    题目大意:

    题目链接:https://jzoj.net/senior/#main/show/5456
    题目图片:
    http://wx1.sinaimg.cn/mw690/0060lm7Tly1fwerg3tpiyj30jf0bigm3.jpg
    http://wx2.sinaimg.cn/mw690/0060lm7Tly1fwerg3u33aj30k40gz3yu.jpg

    给出nn个人的身高,第ii个人记得他的前面或者后面有a[i]a[i]个人比他高。这些人字典序最小的排列。


    思路:

    40分做法:

    先将所有人的身高排序,然后DFSDFS全排列,再判断是否成立。
    时间复杂度:O(n!n2)O(n!n^2)
    代码

    100分做法:

    按照样例一来模拟

    4
    4 1
    3 1
    6 0
    2 0
    

    先按身高排序(从小到大)

    4
    2 0
    3 1
    4 1
    6 0
    

    首先,我们有一个长度为4的空串
    在这里插入图片描述
    身高为2,前(后)面有0个人比他高的人。那么很明显,就只能插入第一个或最后一个位置。
    在这里插入图片描述
    为了字典序最小,那么就将这个人插入到第一个位置。
    在这里插入图片描述
    然后看下一个人,身高为3,前(后)面有一个人比他高。
    那么可能的位置也就只有一个,就插入三号位。

    在这里插入图片描述
    身高为4,前(后)面没有人比他高。
    那么剩余两个位置都有可能。
    在这里插入图片描述
    选择字典序更小的。
    在这里插入图片描述
    那么最后一个人就只能放在最后一个位置了。
    在这里插入图片描述
    那么,我们就需要一个可以插入和查找的数据结构。那么很容易想到权值线段树。
    然后就迎刃而解了。


    代码;

    #include <cstdio>
    #include <algorithm>
    #define N 100100
    using namespace std;
    
    int n,ans[N],f;
    char c;
    
    struct node
    {
    	int h,s;
    }p[N];
    
    struct Tree
    {
    	int l,r,num;
    }tree[N*3];
    
    int read()
    {
    	f=0;
    	c=getchar();
    	while (c<'0'||c>'9') c=getchar();
    	while (c>='0'&&c<='9')
    	{
    		f=f*10+c-48;
    		c=getchar();
    	}
    	return f;
    }
    
    void write(int x)
    {
    	if (x>9) write(x/10);
    	putchar(x%10+48);
    }
    
    bool cmp(node x,node y)
    {
    	return x.h<y.h;
    }
    
    void make(int x)  //建树
    {
    	if (tree[x].l==tree[x].r) 
    	{
    		tree[x].num=1;  //表示这个区间的空位的个数
    		return;
    	}
    	int mid=(tree[x].l+tree[x].r)/2;
    	tree[x*2].l=tree[x].l;
    	tree[x*2].r=mid;
    	tree[x*2+1].l=mid+1;
    	tree[x*2+1].r=tree[x].r;
    	make(x*2);
    	make(x*2+1);
    	tree[x].num=tree[x*2].num+tree[x*2+1].num;
    }
    
    void find(int x,int num,int h)  //查询
    {
    	tree[x].num--;  //空位减一
    	if (tree[x].l==tree[x].r)
    	{
    		ans[tree[x].l]=h;
    		return;
    	}
    	if (num<tree[x*2].num) find(x*2,num,h);  //可以往左就往左
    	else find(x*2+1,num-tree[x*2].num,h);
    }
    
    int main()
    {
    	n=read();
    	for (int i=1;i<=n;i++)
    	 p[i].h=read(),p[i].s=read();
    	sort(p+1,p+1+n,cmp);
    	for (int i=1;i<=n;i++)
    	 if (p[i].s>n-i)
    	 {
    	 	printf("impossible");
    	 	return 0;
    	 }
    	tree[1].l=1;
    	tree[1].r=n;
    	make(1);
    	for (int i=1;i<=n;i++)
    	 find(1,min(p[i].s,n-p[i].s-i),p[i].h);
    	for (int i=1;i<=n;i++)
    	{
    		write(ans[i]);
    		putchar(32);
    	} 
    	return 0;
    }
    
  • 相关阅读:
    软件架构学习小结
    Azure编程笔记(1):序列化复杂类型的TableEntity字段
    目标检測的图像特征提取之(一)HOG特征
    Gmail POP3设置
    MP3的频率、比特率、码率与音质的关系
    Oracle Dataguard 介绍
    【Github教程】史上最全github用法:github入门到精通
    Xcode6在10.9.4上面crash解决
    OpenCV 编程简单介绍(矩阵/图像/视频的基本读写操作)
    调用ShellExecute所须要头文件
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998504.html
Copyright © 2020-2023  润新知