Codeforces 558D - Guess Your Way Out! II (求区间交,并)

题中给出的每一个区间都可以转化为叶子那层的一个区间,所以步骤就是:

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;
}


你可能感兴趣的:(Codeforces 558D - Guess Your Way Out! II (求区间交,并))