洛谷 P2898 [USACO08JAN]haybale猜测Haybale Guessing 解题报告

[USACO08JAN]haybale猜测Haybale Guessing

题目描述

给一段长度为\(n\),每个位置上的数都不同的序列\(a[1\dots n]\)\(q\)和问答,每个问答是\((x, y, r)\)代表\(\min_\limits{i=a}^ba_i= r\), 要你给出最早的有矛盾的那个问答的编号。

输入输出格式

输入格式:

Line 1: Two space-separated integers: \(N\) and \(Q\)

Lines 2..\(Q+1\): Each line contains three space-separated integers that represent a single query and its reply: \(Q_l\), \(Q_h\), and \(A\)

输出格式:

Line 1: Print the single integer \(0\) if there are no inconsistencies among the replies (i.e., if there exists a valid realization of the hay stacks that agrees with all Q queries). Otherwise, print the index from 1..Q of the earliest query whose answer is inconsistent with the answers to the queries before it.


牛客居然考原题...不过题目还是很棒的。

考虑什么情况会产生矛盾。

  1. 两段不相交的区间的最小值相同

  2. 一个最小值大的区间完全覆盖了一个最小值小的区间

  3. 一个区间被其他几个区间完全填充时的,最小值比它们都小。

直接处理很难,如果我们可以按顺序处理的话,比如按最小值从大到小排序,无疑会方便很多,但是回答本身就是带顺序的,我们不可以直接打乱它们。

怎么办呢,二分答案。这无疑是一个很棒的二分答案的思路。正确性很显然。

考虑判断前\(i\)个区间是否产生矛盾,我们按最小值从大到小排序,然后一个一个加入。

  1. 如果当前区间被其他区间完全覆盖,返回不合法。
  2. 如果当前区间与其他区间最小值相同
    • 如果两个区间不交,返回不合法
    • 如果两个区间有交,检查它们的交集是否被别人覆盖,拿它们的并集去覆盖别人。

检查区间覆盖可以通过线段树染色求得,只需要区间赋值\(1\)和区间求和就可以了。


Code:

#include <cstdio>
#include <algorithm>
#include <cstring>
#define rep(i,a,b) for(int i=a;i<=b;i++)
const int N=1e5+10;
int n,q,L[N],R[N],v[N];
struct node
{
    int l,r,v,cl,cr;
    bool friend operator <(node n1,node n2)
    {
        return n1.v==n2.v?n1.l<n2.l:n1.v>n2.v;
    }
    node(){}
    node(int l,int r,int v)
    {
        this->l=l,this->r=r,this->v=v,this->cl=l,this->cr=r;
    }
}Q[N],Q0[N];
const int M=4e6+10;
int tag[M],sum[M];
#define ls id<<1
#define rs id<<1|1
void pushdown(int id,int L,int R)
{
    if(tag[id])
    {
        int Mid=L+R>>1;
        sum[ls]=Mid+1-L,sum[rs]=R-Mid;
        tag[id]=0;tag[ls]=tag[rs]=1;
    }
}
int query(int id,int L,int R,int l,int r)
{
    if(L==l&&R==r) return sum[id];
    pushdown(id,L,R);
    int Mid=L+R>>1;
    if(r<=Mid) return query(ls,L,Mid,l,r);
    else if(l>Mid) return query(rs,Mid+1,R,l,r);
    else return query(ls,L,Mid,l,Mid)+query(rs,Mid+1,R,Mid+1,r);
}
void change(int id,int L,int R,int l,int r)
{
    if(tag[id]) return;
    if(L==l&&R==r)
    {
        sum[id]=R+1-L,tag[id]=1;
        return;
    }
    int Mid=L+R>>1;
    if(r<=Mid) change(ls,L,Mid,l,r);
    else if(l>Mid) change(rs,Mid+1,R,l,r);
    else change(ls,L,Mid,l,Mid),change(rs,Mid+1,R,Mid+1,r);
    sum[id]=sum[ls]+sum[rs];
}
int max(int x,int y){return x>y?x:y;}
int min(int x,int y){return x<y?x:y;}
bool check(int m)
{
    rep(i,1,m) Q[i]=node(L[i],R[i],v[i]);
    std::sort(Q+1,Q+1+m);
    int m_=0;
    rep(i,1,m)
    {
        if(Q[i].v==Q0[m_].v)
        {
            if(Q0[m_].r<Q[i].l) return false;
            else
            {
                Q0[m_].l=Q[i].l;
                Q0[m_].cr=max(Q0[m_].cr,Q[i].r);
                Q0[m_].r=min(Q0[m_].r,Q[i].r);
            }
        }
        else Q0[++m_]=Q[i];
    }
    memset(tag,0,sizeof(tag));
    memset(sum,0,sizeof(sum));
    rep(i,1,m_)
    {
        int l=Q0[i].l,r=Q0[i].r,cl=Q0[i].l,cr=Q0[i].cr;
        if(query(1,1,n,l,r)==r+1-l) return false;
        change(1,1,n,cl,cr);
    }
    return true;
}
int main()
{
    scanf("%d%d",&n,&q);
    rep(i,1,q) scanf("%d%d%d",L+i,R+i,v+i);
    int l=1,r=q;
    if(check(q)) return puts("0"),0;
    while(l<r)
    {
        int mid=l+r>>1;
        if(check(mid)) l=mid+1;
        else r=mid;
    }
    printf("%d\n",l);
    return 0;
}

2018.10.29

posted @ 2018-10-29 20:24  露迭月  阅读(284)  评论(0编辑  收藏  举报