【BZOJ1594】[Usaco2008 Jan]猜数游戏 二分答案+并查集

【BZOJ1594】[Usaco2008 Jan]猜数游戏

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个命题不冲突。

题解:先二分答案,然后将前mid个询问按照A从大到小排序,然后判断:如果几个A比较大的区间的并集包含了一些A比较小的区间的交集,那么一定出现矛盾

区间的包含关系我们可以用一个线段树来维护,当然,另一种神奇的做法就是用并查集

如果我们要覆盖[l,r]这段区间,那么我们就暴力令[l,r]中所有元素的fa都指向r+1,(可以证明均摊的复杂度很小),然后判断某个区间[ll,rr]是否被覆盖过是就看find(ll)是否大于rr就行了

注意所有干草堆的大小都不相同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int n,m;
int f[1000010];
struct QUERY
{
    int qa,qb,qv;
}q[25010],p[25010];
int find(int x)
{
    return (f[x]==x)?x:(f[x]=find(f[x]));
}
bool cmp(QUERY a,QUERY b)
{
    return a.qv>b.qv;
}
bool solve(int sta)
{
    int i,j,l1,l2,r1,r2;
    for(i=1;i<=n+1;i++)    f[i]=i;
    for(i=1;i<=sta;i++)    q[i].qa=p[i].qa,q[i].qb=p[i].qb,q[i].qv=p[i].qv;
    sort(q+1,q+sta+1,cmp);
    l1=l2=q[1].qa,r1=r2=q[1].qb;
    for(i=2;i<=sta;i++)
    {
        if(q[i].qv<q[i-1].qv)
        {
            if(find(l1)>r1)    return false;
            for(j=f[l2];j<=r2;j=f[j])
            {
                find(j);
                f[j]=find(j+1);
            }
            l1=l2=q[i].qa,r1=r2=q[i].qb;
        }
        else
        {
            l1=max(l1,q[i].qa),l2=min(l2,q[i].qa),r1=min(r1,q[i].qb),r2=max(r2,q[i].qb);
            if(r1<l1)    return false;
        }
    }
    if(find(l1)>r1)    return false;
    return true;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)    scanf("%d%d%d",&p[i].qa,&p[i].qb,&p[i].qv);
    int l=1,r=m+1,mid;
    while(l<r)
    {
        mid=l+r>>1;
        if(solve(mid))    l=mid+1;
        else    r=mid;
    }
    printf("%d",l>n?0:l);
    return 0;
}
posted @   CQzhangyu  阅读(761)  评论(5编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示