【BZOJ 1594】 [Usaco2008 Jan]猜数游戏 (二分+并查集)

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

Source

【分析】

  我自己YY是把两个矛盾分开,第一种矛盾,就是要每个数各不相同,比较好弄。然后看看在他之前有没有第二种矛盾,就是最小值的矛盾。

  然后觉得第一种矛盾就用离散,按照右端点排序然后维护后缀最小值处理第二种矛盾。

  不过我打的不是这个方法。

  二分答案,直接看前mid有没有矛盾,按照数值排序,看看有没有交集处理第一种矛盾。

  然后并查集处理已经出现的区间,每个点记录fa的rt,即延伸的最远位置,没有出现的位置直接for,每个空白位置只会扫一次。

  大概就是这样啊,代码超丑ORZ。。

代码如下:

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<queue>
 7 #include<cmath>
 8 using namespace std;
 9 #define Maxn 1000010
10 
11 struct node
12 {
13     int x,y,a;
14 }t[Maxn],tt[Maxn];
15 
16 bool cmp(node x,node y) {return x.a>y.a;}
17 
18 int mymin(int x,int y) {return x<y?x:y;}
19 int mymax(int x,int y) {return x>y?x:y;}
20 
21 int n;
22 
23 int rt[Maxn],fa[Maxn];
24 
25 int ffind(int x)
26 {
27     if(fa[x]!=x) fa[x]=ffind(fa[x]);
28     return fa[x];
29 }
30 
31 bool check(int now)
32 {
33     memset(rt,-1,sizeof(rt));
34     for(int i=1;i<=now;i++) tt[i]=t[i];
35     for(int i=1;i<=n;i++) fa[i]=i;
36     sort(tt+1,tt+1+now,cmp);
37     for(int i=1;i<=now;i++)
38     {
39         int lm=tt[i].x,rm=tt[i].y,lx=tt[i].x,rx=tt[i].y;
40         while(i<now&&tt[i].a==tt[i+1].a)
41         {
42             lx=mymax(lx,tt[i+1].x);
43             rx=mymin(rx,tt[i+1].y);
44             lm=mymin(lm,tt[i+1].x);
45             rm=mymax(rm,tt[i+1].y);
46             i++;
47         }
48         if(lx>rx) return 1;
49         if(rt[ffind(lx)]>=rx) return 1;
50         if(rt[ffind(lm)]==-1) rt[ffind(lm)]=lm;
51         for(int j=rt[ffind(lm)];j<rm;)
52         {
53             if(rt[ffind(j+1)]==-1) rt[ffind(j+1)]=j+1;
54             fa[ffind(j)]=ffind(j+1);
55             j=rt[ffind(j+1)];
56         }
57         if(rt[ffind(rm+1)]!=-1) fa[ffind(rm)]=ffind(rm+1);
58         if(rt[ffind(lm-1)]!=-1) fa[ffind(lm-1)]=ffind(lm);
59     }
60     return 0;
61 }
62 
63 void ffind(int l,int r)
64 {
65     int ans=0;
66     while(l<r)
67     {
68         int mid=(l+r)>>1;
69         if(check(mid)) r=mid,ans=mid;
70         else l=mid+1;
71     }
72     printf("%d
",ans);
73 }
74 
75 int main()
76 {
77     int q;
78     scanf("%d%d",&n,&q);
79     for(int i=1;i<=q;i++) scanf("%d%d%d",&t[i].x,&t[i].y,&t[i].a);
80     ffind(1,q);
81     return 0;
82 }
[BZOJ J1594]

同样是并查集为啥我的就那么慢。。TAT。。。

2016-10-28 14:48:53

原文地址:https://www.cnblogs.com/Konjakmoyu/p/6007782.html