题中给出的每一个区间都可以转化为叶子那层的一个区间,所以步骤就是:
1.对于所有ans=1的区间求区间交,方法很简单就是两个l取最大值,r取最小值,最后答案一定在这里面。
2.对于ans=0的区间,求区间并的补集。方法是用一个pair,对每个区间的左端点附加信息-1,右端点附加信息1,排序后从左往右扫,累加这个附加信息,当累加和等于0时,说明在该点前的所有区间都结束了,那么从这个点到下一个区间的起点这一段是可能有答案的区间。
注意要把总区间的左右端点也加紧取才能保证不遗漏区间。
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#include <vector>
#define mp(a,b) make_pair(a,b)
#define pb(a) push_back(a)
#define LL long long
vector <pair<LL,int> > G;
vector <pair<LL,LL> > N;
int main(){
int H,Q;
LL L,R;
scanf("%d%d",&H,&Q);
L=1;
for(int i=0;i<H-1;i++){
L*=2;
}
R=L*2-1;
LL al=L,ar=R;
for(int i=0;i<Q;i++){
int lv,k;
LL l,r;
scanf("%d%lld%lld%d",&lv,&l,&r,&k);\
r++;
for(int i=0;i<H-lv;i++){
l*=2; r*=2;
}
r--;
if(k){
al=max(al,l);
ar=min(ar,r);
}
else {
G.pb(mp(l,-1)); G.pb(mp(r,1));
}
}
G.pb(mp(L-1,0));G.pb(mp(R+1,0));
if(al>ar) { printf("Game cheated!\n"); return 0; }
sort(G.begin(),G.end());
int tot=0;
for(int i=0;i<G.size()-1;i++){
tot+=G[i].second;
if(tot==0){
N.pb(mp(G[i].first+1,G[i+1].first-1));
}
}
LL num=0;
LL res=-1;
for(int i=0;i<N.size();i++){
LL cl=N[i].first,cr=N[i].second;
if(cl>cr) continue;
cl=max(cl,al);
cr=min(cr,ar);
if(cr>=cl){
num+=(cr-cl+1);
res=cr;
}
}
if(num>1){
printf("Data not sufficient!\n");
}
else if(num==0){
printf("Game cheated!\n");
}
else printf("%lld\n",res);
return 0;
}