题目链接:http://codeforces.com/contest/558/problem/D
题意就是有一个二叉树高度为 h ,人站在根节点上,现在要走出去,出口在叶子节点上,有 q 条信息,每条信息包含了在第 x 层的节点 L 到 R 范围内的叶子节点中是否存在出口,ans=1代表包含,ans=0代表不包
含;求出出口的节点,如果不存在输出Game cheated! 如果出口不止一个输出Data not sufficient!
对左右区间起点和终点组成的集合进行排序。然后找到答案存在的区间,如果区间长度=1,答案唯一;长度>1,答案不唯一;长度=0,无解。
我们可以把所有的第x层的L R节点在第h层找到相对应的L R,最后转移到求第h层的区间覆盖数为 q 的节点;
由于数据超int,一定开不了数组,就用map<LL, int>容器(自带排序);在LL进行位运算是要把1转成LL类型,错的我想哭;
#include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> #include <math.h> #include <vector> #include <map> using namespace std; #define N 55 #define INF 0x3f3f3f3f #define met(a, b) memset(a, b, sizeof(a)) typedef long long LL; int main() { LL L[N] = {0, 1}, R[N] = {0}; /// LL L1[N] = {0, 1}; for(int i=2; i<=50; i++) { L[i] = L[i-1]*2; /// L1[i] = (LL)1 << (i-1) ;///long long 的位运算要这样写; /// printf("%I64d %I64d ", L[i], L1[i]); R[i] = L[i]*2-1; } int h, q, x, ans; LL Right, Left; while(scanf("%d %d", &h, &q) != EOF) { if (q == 0) { if (h == 1)puts("1"); else puts("Data not sufficient!"); continue ; } map<LL, int> a;///自带排序功能,按照LL类型的数进行从小到大的顺序排列; for(int i=1; i<=q; i++) { scanf("%d %I64d %I64d %d", &x, &Left, &Right, &ans); while(x < h) { x ++; Left = Left * 2; Right = Right * 2 + 1; } if(ans) { a[Left] ++; a[Right+1] --; } else { a[L[h]] ++; a[Left] --; a[Right+1] ++; a[R[h]+1] --; } } int sum = 0; LL ans1, cnt = 0, Mid = -1; map<LL, int>:: iterator it; for(it = a.begin() ; it != a.end(); it ++)///map类型内数据的访问; { ///printf("%I64d %d ", it->first, it->second); sum += ( it->second );///类似区间覆盖问题; if( Mid != -1 ) { cnt += ( it->first ) - Mid;///记录区间范围; ans1 = Mid; } if( sum == q ) Mid = ( it->first );///说明每局询问里面都允许it->first是答案; else Mid = -1; } if(cnt == 1) printf("%I64d ", ans1);///当答案所在的区间==1时,mid就是答案; else if(cnt > 1) puts("Data not sufficient!");///范围大于一时说明数据不足; else puts("Game cheated!");///==0时说明有错; } return 0; }