51nod 1484-猜数游戏(区间交+区间并->map)

题目来源:  CodeForces
基准时间限制:1 秒 空间限制:131072 KB 分值: 40  难度:4级算法题
 收藏
 关注

现在有一款小游戏叫做“猜数游戏”。这个游戏的目的是从一个迷宫中找到一个出口。这个迷宫的形状是一棵高度为h的完全二叉树。玩家刚开始站在根部,出口是在某一个叶子结点上面。

现在我们来定义每一个结点的编号:

·        根部是1

·        某个内部结点的编号为  i (i  2h11)  时,他的左儿子编号为2i,右儿子编号为2i+1。

根的深度定为1,其它结点的深度是他的父亲的深度+1。深度为h的结点是叶子。出口在某个叶子结点上,但是游戏玩家并不知道在哪个叶子,所以他现在要开始猜。

玩家每次会问ancestor(exit, i)属于[L,R]吗?这儿 ancestor(v, i) 表示结点v在第i层的那个祖先。然后游戏会给出"Yes"或"No"的回答。这个游戏的回答也不一定是完全合法的。有一些时候他会骗玩家。

现在有一些询问和回答,要求你从中判断一下,这个游戏有没有在说谎。如果游戏没有说谎,并且出口被推断出来,那么请输出出口,如果游戏没有说谎,但是出口不能被唯一判定出来,请输出“Data not sufficient!”。否则输出“Game cheated!”

结点u是结点v的祖先,当且仅当满足以下条件之一:

·        u和v一样,

·        u 是 v的父亲,

·        u 是v的父亲的祖先。

 

样例解释:在这个例子中有 8个叶子结点。经过第一个询问之后,出口被确定在 [10, 14]区间内。经过第二个和第三个询问,只有14号符合条件。请结合图例进行理解。


Input
单组测试数据。
第一行有两个整数h, q (1 ≤ h ≤ 50, 1 ≤ q ≤ 10^5),表示树的高度和询问的数量。
接下来q行,每行包含 i, L, R, ans (1 ≤ i ≤ h, 2^(i - 1) ≤ L ≤ R ≤ 2^i - 1, ans∈{0,1}),表示询问出口在第i层的祖先属于L,R吗?ans=1表示YES,否则表示NO。
Output
如果游戏给出的信息是自相矛盾的,那么输出 Game cheated!。
如果可以唯一确定出口。那么输出出口的编号。
否则输出Data not sufficient!。
Input示例
4 3
4 10 14 1
3 6 6 0
2 3 3 1
Output示例
14
System Message  (题目提供者)
C++的运行时限为:1000 ms ,空间限制为:131072 KB  示例及语言说明请按这里

 允许其他 AC 的用户查看此代码,分享代码才能查看别人的代码并有机会获得勋章

一开始想着模拟,太年轻了,然后超时了。。。

后来感觉要把他们转化成区间问题,但是想想有些小问题,看了发题解,发现就是区间交的问题23333.

其实每次的询问我们都可以把出口包含在合法区间内。。

当w=1时,则出口一定在[y,z]内,当w=0时,出口必在[l,y-1]或[z+1,r];内。(其中l,r为最后一层的两端)

故我们只需在最后查询结束后,看是否存在且只存在一个点被覆盖q次即可。。。。。

#include<map>       
#include<stack>              
#include<queue>              
#include<vector>      
#include<string>    
#include<math.h>              
#include<stdio.h>              
#include<iostream>              
#include<string.h>              
#include<stdlib.h>      
#include<algorithm>     
#include<functional>      
using namespace std;
typedef long long  ll;
#define inf  1000000000         
#define mod 1000000007               
#define maxn  2386000    
#define PI 3.1415926  
#define lowbit(x) (x&-x)              
#define eps 1e-9    
ll a[maxn], l[55], r[55];
map<ll, int>p;
int main(void)
{
	ll n, q, i, j, x, y, z, w, h;
	l[1] = r[1] = 1;
	for (i = 2;i <= 50;i++)
		l[i] = l[i - 1] * 2, r[i] = r[i - 1] * 2 + 1;
	scanf("%lld%lld", &h, &q);
	if (q == 0)
	{
		if (h == 1)
			printf("1\n");
		else
			printf("Data not sufficient!\n");
		return 0;
	}
	int num = q;
	while (q--)
	{
		scanf("%lld%lld%lld%lld", &x, &y, &z, &w);
		ll ls = y, rs = z;
		while (x < h)
		{
			ls *= 2;
			rs = rs * 2 + 1;
			x++;
		}
		if (w == 1)
			p[ls]++, p[rs + 1]--;
		else
		{
			p[l[h]]++;p[ls]--;
			p[rs + 1]++;p[r[h]+1]--;
		}
	}
	int sum = 0;
	ll pre = -1, cnt = 0, ans = 0;
	map<ll, int>::iterator it;
	for (it = p.begin();it != p.end();it++)
	{
		sum += it->second;
		//printf("%d\n", sum);
		if (pre != -1)
		{
			cnt += it->first - pre;
			ans = pre;
		}
		if (sum == num)
			pre = it->first;
		else
			pre = -1;
	}
	if (cnt == 0)
		printf("Game cheated!\n");
	else if (cnt > 1)
		printf("Data not sufficient!\n");
	else
		printf("%lld\n", ans);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值