1. 程式人生 > >【bzoj1594】猜數遊戲

【bzoj1594】猜數遊戲

在哪裏 min 依次 vector 包括 eof ron clas logs

1594: [Usaco2008 Jan]猜數遊戲

Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 556 Solved: 225

Description

為了提高自己低得可憐的智商,奶牛們設計了一個新的猜數遊戲,來鍛煉她們的邏輯推理能力。 遊戲開始前,一頭指定的奶牛會在牛棚後面擺N(1 <= N<= 1,000,000)堆幹草,每堆有若幹捆,並且沒有哪兩堆中的草一樣多。所有草堆排成一條直線,從左到右依次按1..N編號,每堆中草的捆數在1..1,000,000,000之間。 然後,遊戲開始。另一頭參與遊戲的奶牛會問那頭擺幹草的奶牛 Q(1 <= Q <= 25,000)個問題,問題的格式如下: 編號為Ql..Qh(1 <= Ql <= Qh <= N)的草堆中,最小的那堆裏有多少捆草? 對於每個問題,擺幹草的奶牛回答一個數字A,但或許是不想讓提問的奶牛那麽容易地得到答案,又或許是她自己可能記錯每堆中幹草的捆數,總之,她的回答不保證是正確的。 請你幫助提問的奶牛判斷一下,擺幹草的奶牛的回答是否有自相矛盾之處。

Input

* 第1行: 2個用空格隔開的整數:N 和 Q

* 第2..Q+1行: 每行為3個用空格隔開的整數Ql、Qh、A,描述了一個問題以及它 對應的回答

Output

* 第1行: 如果擺幹草的奶牛有可能完全正確地回答了這些問題(也就是說,能 找到一種使得所有回答都合理的擺放幹草的方法),輸出0,否則輸出 1個1..Q中的數,表示這個問題的答案與它之前的那些回答有沖突之處

Sample Input

20 4
1 10 7
5 19 7
3 12 8
11 15 12

輸入說明:

編號為1..10的草堆中,最小的那堆裏有7捆草,編號為5..19的草堆中同樣
如此;編號為3..12的草堆中最小的堆裏是8捆草,11..15堆中的最小的堆裏是12
捆。

Sample Output

3

輸出說明:

對於第3個問題“3 12”的回答“8”與前面兩個回答沖突。因為每堆中草的
捆數唯一,從前兩個回答中我們能推斷出,編號為5..10的幹草堆中最小的那堆
裏有7捆幹草。很顯然,第3個問題的回答與這個推斷沖突。

HINT

註意:如果有沖突出現輸出一個數m,使得前M-1個命題不沖突。

試題分析:首先要確定在什麽情況下會出現矛盾:

      1.當存在一個(x1,y1,r)與另一個三元組(x,y,r)兩個區間不相交時不存在解

      2.當存在一個(x1,y1,r1)與另一個三元組(x,y,r)中,r1>r,[x1,y1]包括[x,y],那麽顯然此情況不合法。

     第一個判斷只需要順次判斷記錄一個交集一個並集即可,第二個判斷線段樹維護。

     此時會發現一個問題,順次修改並不能判斷1在哪裏出現矛盾或判斷在2出現矛盾。

     這樣我們就需要考慮二分一個答案,然後檢驗這個答案以及之前是否會出現矛盾。

     先離散化一下r,然後對於每個r求出其詢問的交集和並集。

     然後我們就可以知道判斷1只需要使用交集判斷,如果一個r的詢問和之前r詢問的交集沒有相交,那麽就矛盾。

     對於判斷2,從Q~1枚舉r,我們的線段樹只需要維護一下兩個操作:

      1.查詢區間與運算

      2.將一段區間置為1

     這是很好維護的,然後註意一點,取區間與需要判斷的是交集,而詢問中(x,y,r)相當於聲明[x,y]這段區間的最小值已經是r了,那麽就需要在線段樹中將[x並,y並](對於詢問答案r的)這一段區間置為1,而不是取交集置為1。

代碼:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
inline int read(){
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c==‘-‘) f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-‘0‘;
    return x*f;
}
const int MAXN = 1000001;
const int INF = 999999;
int N,Q;
struct data{
    int x,y,r;
    int id;
}a[MAXN+1];
int ans; int P[MAXN+1],cnt;
bool cmp(data a,data b){
    return a.r<b.r;
}
struct row{
    int x,y;
    int x1,y1;
}t[MAXN+1];
int tr[MAXN*4+1];
int col[MAXN*4+1];

int mint(int a,int b){
    return min((a==INF?-INF:a),(b==INF?-INF:b));
}
void Lazy_tage(int l,int r,int rt){
    if(!col[rt]) return ;
    tr[rt*2]=1; tr[rt*2+1]=1; tr[rt]=1;
    col[rt*2]=1; col[rt*2+1]=1;
    col[rt]=0;
}
int Min(int rt,int l,int r,int L,int R){
    if(L<=l&&R>=r){
        return tr[rt];
    }
    Lazy_tage(l,r,rt);
    int mid=(l+r)>>1,ans=1;
    if(mid>=L) ans=ans&Min(rt*2,l,mid,L,R);
    if(mid<R) ans=ans&Min(rt*2+1,mid+1,r,L,R);
    return ans;
}
void Add(int rt,int l,int r,int L,int R){
    if(L<=l&&R>=r){
        tr[rt]=1;
        col[rt]=1;
        return ;
    }
    Lazy_tage(l,r,rt);
    int mid=(l+r)>>1;
    if(mid>=L) Add(rt*2,l,mid,L,R);
    if(mid<R) Add(rt*2+1,mid+1,r,L,R);
    tr[rt]=tr[rt*2]&tr[rt*2+1];
    return ;
}

bool check(int k){
    memset(tr,0,sizeof(tr));
    memset(col,0,sizeof(col));
    for(int i=1;i<=Q;i++)
        t[i].x=t[i].y=-1;
    for(int i=1;i<=Q;i++){
        if(a[i].id>k) continue;
        if(t[a[i].r].x==-1){
            t[a[i].r].x=a[i].x;//x,y為並集
            t[a[i].r].y=a[i].y;
            t[a[i].r].x1=a[i].x;//x1,y1為交集
            t[a[i].r].y1=a[i].y;
        }
        else{
            if(a[i].x>t[a[i].r].y||a[i].y<t[a[i].r].x) return false;
            t[a[i].r].x=max(t[a[i].r].x,a[i].x);
            t[a[i].r].y=min(t[a[i].r].y,a[i].y);
            t[a[i].r].x1=min(t[a[i].r].x1,a[i].x);
            t[a[i].r].y1=max(t[a[i].r].y1,a[i].y);
        }
    }
    for(int i=Q;i>=1;i--){
        if(t[i].x!=-1){
            int op=Min(1,1,N,t[i].x,t[i].y);//查詢r的並集,只有並集中才可能出現r
            if(op==1) return false;
            Add(1,1,N,t[i].x1,t[i].y1);//這裏需要將交集加上
        }
    }
    return true;
}

int main(){
    N=read(),Q=read();
    for(int i=1;i<=Q;i++){
        a[i].x=read(); a[i].y=read();
        a[i].r=read(); P[++cnt]=a[i].r;
        a[i].id=i;
    }
    sort(P+1,P+cnt+1);
    for(int i=1;i<=Q;i++) a[i].r=lower_bound(P+1,P+cnt+1,a[i].r)-P;//離散化r
    sort(a+1,a+Q+1,cmp);
    int l=1,r=Q;
    while(l<=r){
        int mid=(l+r)>>1;
        if(check(mid)) ans=mid,l=mid+1;
        else r=mid-1;
    }
    printf("%d\n",(ans+1)%(Q+1));
}

  

【bzoj1594】猜數遊戲