D. Guess Your Way Out! II
Problem's Link: http://codeforces.com/problemset/problem/558/D
Mean:
一棵满二叉树,树中某个叶子节点是出口,目的是寻找这个出口。再给定Q个询问的结果,每个结果告诉我们在第i层中(l,r)覆盖的叶结点是否包含出口。
analyse:
基本思路:多个区间求交集。
具体实现:
对于每一个询问,把它转化到最底层。并且把不在(l,r)区间的询问改为在(最左边,l-1)和(r+1,最右边)的形式,这样一来全部都变成了在(l,r)区间的描述。
区间统计:
对左右区间起点和终点组成的集合进行排序。然后找到答案存在的区间,如果区间长度=1,答案唯一;长度>1,答案不唯一;长度=0,无解。
Trick:会爆int。
Time complexity: O(n)
Source code:
/* * this code is made by crazyacking * Verdict: Accepted * Submission Date: 2015-07-16-11.55 * Time: 0MS * Memory: 137KB */ #include <queue> #include <cstdio> #include <set> #include <string> #include <stack> #include <cmath> #include <climits> #include <map> #include <cstdlib> #include <iostream> #include <vector> #include <algorithm> #include <cstring> #define LL long long #define ULL unsigned long long using namespace std; LL L[51], R[51]; int main() { ios_base::sync_with_stdio( false ); cin.tie( 0 ); L[1] = 1, R[1] = 1; for( int i = 2; i <= 50; ++i ) L[i] = L[i - 1] << 1, R[i] = ( L[i] << 1 ) - 1; int h, q; cin >> h >> q; if( q == 0 ) { if( h == 1 ) puts( "1" ); else puts( "Data not sufficient!" ); return 0; } map<LL, int> mp; for( int i = 0; i < q; ++i ) { LL level, left, right, type, gap; cin >> level >> left >> right >> type; gap = h - level; while( gap ) { gap--; left <<= 1; right = ( ( right + 1 ) << 1 ) - 1; } if( type ) { mp[left]++; mp[right + 1]--; } else { mp[L[h]]++; mp[left]--; mp[right + 1]++; mp[R[h] + 1]--; } } LL ans, sum = 0, ans_gap = 0, mid_pre = -1; map<LL, int>:: iterator it = mp.begin(); for( ; it != mp.end(); ++it ) { sum += ( it->second ); if( mid_pre != -1 ) { ans_gap += ( it->first ) - mid_pre; ans = mid_pre; } if( sum == q ) mid_pre = ( it->first ); else mid_pre = -1; } if( ans_gap == 1 ) cout << ans << endl; else if( ans_gap > 1 ) puts( "Data not sufficient!\n" ); else puts( "Game cheated!\n" ); return 0; } /* */