51Nod 1484 - 猜数游戏(离散化)

51Nod 1484 - 猜数游戏(离散化)_第1张图片

【思路】
把输入的每一个区间都下放到树的最后一层上,把树的最后一层看成一个序列,问题就转换成了求若干区间的交集和并集,交集比较好求,维护左右断点值即可。求并集需要将区间端点离散化后再处理,参考了大佬的代码,比较诡异,不是很懂正确性。还要注意的是,离散化完以后是一个点,对应原来的序列可能是一个区间,也可能是一个点,需要特殊判断,所以在离散化的时候不仅需要把区间的左右端点加入,还要把它们的前一个点和后一个点也加进来。

#include
using namespace std;
typedef long long ll;
typedef pair pll;
const int maxn=1e5+5;

int h,q,d,ok;
ll pw[55],le,ri,maxl,minr;

ll v[maxn*6];int tot;
pll a[maxn];int cnt;
int sum[maxn*6];

int main(){
    pw[0]=1;
    for(int i=1;i<55;++i) pw[i]=pw[i-1]*2;
    scanf("%d%d",&h,&q);
    maxl=pw[h-1],minr=pw[h]-1;
    while(q--){
        scanf("%d%lld%lld%d",&d,&le,&ri,&ok);
        while(dminr){
        puts("Game cheated!");
        return 0;
    }
    sort(v+1,v+1+tot);
    tot=unique(v+1,v+1+tot)-(v+1);
    for(int i=1;i<=cnt;++i){
        int pl=lower_bound(v+1,v+1+tot,a[i].first)-v;
        int pr=lower_bound(v+1,v+1+tot,a[i].second)-v;
        ++sum[pl];
        --sum[pr+1];
    }
    for(int i=1;i<=tot;++i) sum[i]+=sum[i-1];
    for(int i=1;i<=tot;++i){
        sum[i]=min(sum[i],1);
        sum[i]+=sum[i-1];
    }
    int pl=lower_bound(v+1,v+1+tot,maxl)-v;
    int pr=lower_bound(v+1,v+1+tot,minr)-v;
    if(pr-pl+1==sum[pr]-sum[pl-1]){
        puts("Game cheated!");
    }
    else if(pr-pl+1>sum[pr]-sum[pl-1]+1){
        puts("Data not sufficient!");
    }
    else{
        for(int i=pl;i<=pr;++i){
            if(sum[i]==sum[i-1]){
                if(i==1){
                    if(v[i]+1==v[i+1]) printf("%lld\n",v[i]);
                    else puts("Data not sufficient!");
                }
                else if(i==tot){
                    if(v[i-1]+1==v[i]) printf("%lld\n",v[i]);
                    else puts("Data not sufficient!");
                }
                else{
                    if(v[i-1]+1==v[i] && v[i]+1==v[i+1]) printf("%lld\n",v[i]);
                    else puts("Data not sufficient!");
                }
                break;
            }
        }
    }
    return 0;
}

你可能感兴趣的:(常用技巧)