Codeforces 558D Guess Your Way Out! II(区间的交+并+补)

题面

Amr bought a new video game "Guess Your Way Out! II". The goal of the game is to find an exit from the maze that looks like a perfect binary tree of height h. The player is initially standing at the root of the tree and the exit from the tree is located at some leaf node.

Let's index all the nodes of the tree such that

  • The root is number 1
  • Each internal node i (i ≤ 2h - 1 - 1) will have a left child with index = 2i and a right child with index = 2i + 1

The level of a node is defined as 1 for a root, or 1 + level of parent of the node otherwise. The vertices of the level h are called leaves. The exit to the maze is located at some leaf node n, the player doesn't know where the exit is so he has to guess his way out!

In the new version of the game the player is allowed to ask questions on the format "Does the ancestor(exit, i) node number belong to the range [L, R]?". Here ancestor(v, i) is the ancestor of a node v that located in the level i. The game will answer with "Yes" or "No" only. The game is designed such that it doesn't always answer correctly, and sometimes it cheats to confuse the player!.

Amr asked a lot of questions and got confused by all these answers, so he asked you to help him. Given the questions and its answers, can you identify whether the game is telling contradictory information or not? If the information is not contradictory and the exit node can be determined uniquely, output its number. If the information is not contradictory, but the exit node isn't defined uniquely, output that the number of questions is not sufficient. Otherwise output that the information is contradictory.

Input

The first line contains two integers h, q (1 ≤ h ≤ 50, 0 ≤ q ≤ 105), the height of the tree and the number of questions respectively.

The next q lines will contain four integers each i, L, R, ans (1 ≤ i ≤ h, 2i - 1 ≤ L ≤ R ≤ 2i - 1, ), representing a question as described in the statement with its answer (ans = 1 if the answer is "Yes" and ans = 0 if the answer is "No").

Output

If the information provided by the game is contradictory output "Game cheated!" without the quotes.

Else if you can uniquely identify the exit to the maze output its index.

Otherwise output "Data not sufficient!" without the quotes.

Examples

Input

3 1
3 4 6 0

Output

7

Input

4 3
4 10 14 1
3 6 6 0
2 3 3 1

Output

14

Input

4 2
3 4 6 1
4 12 15 1

Output

Data not sufficient!

Input

4 2
3 4 5 1
2 3 3 1

Output

Game cheated!

Note

Node u is an ancestor of node v if and only if

  • u is the same node as v,
  • u is the parent of node v,
  • or u is an ancestor of the parent of node v.

In the first sample test there are 4 leaf nodes 4, 5, 6, 7. The first question says that the node isn't in the range [4, 6] so the exit is node number 7.

In the second sample test there are 8 leaf nodes. After the first question the exit is in the range [10, 14]. After the second and the third questions only node number 14 is correct. Check the picture below to fully understand.

题目链接

Codeforces_558D

参考链接

Codeforces Round #312 (Div. 2) D. Guess Your Way Out! II (求区间的补、交)author:fukan

题目简述

这是一个完全二叉树一共有h层,其中一个叶子结点是迷宫的出口,现在需要根据题目提供的q次询问和答案来判断出口的位置。

对于每个询问,问:“出口在第i层的祖先”的序号在[L,R]之间吗?(L、R与“出口在第i层的祖先”在同一层)如果是,ans=1,否则ans=0。

先根据i,L,R处理出在叶子结点层对应的区间[L,R](以下L,R均为处理过的),对于这些区间依次进行如下操作:

①对于ans==1的询问,则一个个地与已有答案answer取交集(answer的初始值为全集)

②对于ans==0的询问,得到两根扫描线:

   第一根:位置在L,标记值为1

   第二根:位置在R,标记值为-1

   对于所有扫描线重新排序,遍历这些线,用sign记录标记值得前缀和。

   当sign==0时,说明经过的扫描线数目为偶数,标记值为1和-1的线各一半,即经过若干个完整的区间。那么当前扫描线和下一根扫描线之间的区间,一定是(ans==0的区间的并集相对于全集的)补集的一部分。将这个区间与“操作①”得到的结果求交集。

一定要区分以下两种情况:(Wrong answer on test 11

①没有ans==0的询问,即line_num==0。调用了操作②的函数,造成无解的假象。

②有ans==0的询问,但把全集覆盖了,造成无解。

程序分析

int h;
struct Node/**区间**/
{
    long long left,right;
}node[maxn];
int node_num;

struct Line/**扫描线**/
{
    long long where;
    int flag;
}line[maxn*2];
int line_num;

bool cmp_line(const Line &a,const Line &b)/**扫描线排序规则**/
void read(int i,long long L,long long R,int ans)/**对于每个询问进行初步处理**/
Node deal_positive()/**处理ans==1的询问**/
Node deal_negative(Node x)/**处理ans==0的询问**/
Node work()

answer.left==-1无解

answer.left==-2信息不足/有多个解

程序

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define maxn 100005
int h;
struct Node/**区间**/
{
    long long left,right;
}node[maxn];
int node_num;

struct Line/**扫描线**/
{
    long long where;
    int flag;
}line[maxn*2];
int line_num;

bool cmp_line(const Line &a,const Line &b)/**扫描线排序规则**/
{
    if(a.where!=b.where)
        return a.where<b.where;
    else
        return a.flag<b.flag;
}

void read(int i,long long L,long long R,int ans)/**对于每个询问进行初步处理**/
{
    for(int j=i+1;j<=h;j++)
    {
        L*=2;
        R=R*2+1;
    }
    if(ans==1)
    {
        node[node_num].left=L;
        node[node_num].right=R;
        node_num++;
    }
    else
    {
        line[line_num].flag=1;
        line[line_num].where=L;
        line_num++;
        line[line_num].flag=-1;
        line[line_num].where=R;
        line_num++;
    }
}

Node deal_positive()/**处理ans==1的询问**/
{
    Node answer;
    answer.left=1;
    answer.right=1;
    for(int i=2;i<=h;i++)
    {
        answer.left*=2;
        answer.right=answer.right*2+1;
    }
    for(int i=0;i<node_num;i++)
    {
        answer.left=max(answer.left,node[i].left);
        answer.right=min(answer.right,node[i].right);
        if(answer.left>answer.right)
        {
            answer.left=answer.right=-1;/**无解**/
            return answer;
        }
    }
    return answer;
}

Node deal_negative(Node x)/**处理ans==0的询问**/
{
    int sign=0;
    Node answer;
    answer.left=answer.right=-1;

    Node temp;
    temp.left=1;
    for(int i=2;i<=h;i++)
        temp.left*=2;
    temp.right=line[0].where-1;
    if(temp.left<=temp.right&&max(x.left,temp.left)<=min(x.right,temp.right))/**最左端点到第一根扫描线之间的区间**/
    {
        answer.left=max(x.left,temp.left);
        answer.right=min(x.right,temp.right);
    }
    for(int i=0;i<line_num;i++)
    {
        sign+=line[i].flag;
        if(sign==0)/**当前扫描线到下一根扫描线之间的区间**/
        {
            temp.left=line[i].where+1;
            if(i==line_num-1)
            {
                temp.right=1;
                for(int i=2;i<=h;i++)
                    temp.right=temp.right*2+1;
            }
            else
                temp.right=line[i+1].where-1;
            if(temp.left<=temp.right&&max(x.left,temp.left)<=min(x.right,temp.right))
            {
                if(answer.left!=-1)
                {
                    answer.left=answer.right=-2;
                    return answer;
                }
                answer.left=max(x.left,temp.left);
                answer.right=min(x.right,temp.right);
            }
        }
    }
    return answer;
}

Node work()
{
    Node answer=deal_positive();
    if(answer.left==-1)
        return answer;
    if(line_num>0)
        answer=deal_negative(answer);
    if(answer.left!=answer.right)
    {
        answer.left=answer.right=-2;
    }
    return answer;
}

int main()
{
    int q;
    node_num=0;
    line_num=0;
    scanf("%d%d",&h,&q);
    while(q--)
    {
        int i,ans;
        long long L,R;
        scanf("%d%lld%lld%d",&i,&L,&R,&ans);
        read(i,L,R,ans);
    }
    sort(line,line+line_num,cmp_line);
    Node answer=work();
    if(answer.left==-1)
        printf("Game cheated!");
    else if(answer.right==-2)
        printf("Data not sufficient!");
    else
        printf("%lld\n",answer.left);
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值