poj-3657 Haybale Guessing(二分答案+并查集)

http://poj.org/problem?id=3657

下方有中文版,不想看英文的可直接点这里看中文版题目

Description

The cows, who always have an inferiority complex about their intelligence, have a new guessing game to sharpen their brains.

A designated 'Hay Cow' hides behind the barn and creates N (1 ≤ N ≤ 1,000,000) uniquely-sized stacks (conveniently numbered 1..N) of hay bales, each with 1..1,000,000,000 bales of hay.

The other cows then ask the Hay Cow a series of Q (1 ≤ Q ≤ 25,000) questions about the the stacks, all having the same form:

What is the smallest number of bales of any stack in the range of stack numbers Ql..Qh (1 ≤ Ql ≤ NQl ≤ Qh ≤ N)?

The Hay Cow answers each of these queries with a single integer A whose truthfulness is not guaranteed.

Help the other cows determine if the answers given by the Hay Cow are self-consistent or if certain answers contradict others.

Input

* 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: QlQh, and A

Output

* 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.

Sample Input

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

Sample Output

 3

说明

The minimum number of bales in stacks 1..10 is 7, the minimum number of bales in stacks 5..19 is 7, the minimum number of bales in stacks 3..12 is 8, and the minimum number of bales in stacks 11..15 is 12.
Query 3 ("3 12 8") is the first that is inconsistent with those before it. From queries 1 and 2 and the fact that all hay stacks have a distinct number of bales, we deduce that one of stacks 5..10 must contain exactly 7 bales. However, this stack contradicts the answer to query 3.

 

中文版

题意:

 给一段长度为n,每个位置上的数都不同的序列a[1..n]和q和问答,然后给出q个区间及其区间最小值,求出到第几个区间会出现矛盾

思路:

1.二分+线段树(暂时不会,以后填坑) 

2.二分+并查集(并查集用来区间染色)//并查集有个经典用法--区间染色,所以用并查集维护

首先 如果我们想知道这头奶牛之前的奶牛回答的是不是错的怎么办呢?

把回答的A从大到小排个序。这里有几种矛盾的方式:

  • 如果后面的区间完全被前面的区间包含,这是错的
  • 如果有两个不相交的区间的A是一样的,这也是错的(题目保证没有两堆干草的数量是一样的)

注意取相同A的区间的时候不要超过当前二分的mid

以下题解部分参考于:https://blog.csdn.net/wang2147483647/article/details/60142150

由于每个位置的数唯一,对于两个区间[l,r]最小值为a、[L,R]最小值为A。

若区间[l,r]被区间[L,R]完全包含且a<A,此时存在矛盾且为唯一的矛盾。

则可以二分询问Q,判断1---tot内的询问是否合法。每次二分时,将1---tot之间的询问按照最小值从大到小排序(优先处理大数,以后判断时仅需判断小数所在的区间是否被大数所在区间包含)。

由于每个数唯一,对于每个最小值相同的区间,判断其交集是否为空或者是否在更大最小值的区间中,此时出现矛盾,继续二分。

若未出现矛盾,则将其并集染色(这样判断矛盾时若交集所在区间中无未染色区间,则交集在最小值更大的区间中(最小值从大到小排序,更大最小值的区间已被全部染色,若无未染色区间,则说明此区间在最小值更大区间中))。

染色若用线段树,则无优化下会超时,所以可用并查集处理染色:对于一段区间[l,r]若将其染色,则设fa[r]=l-1(不可为l,因为l也为已染色点,例如数据 1 2 1和1 2 2),代表[l,r]中的数已全部染色(从后向前找对于每一个区间中的点都可以直接跳到其父节点,因为该区间已被全部染色),则判断时若l>Find(r)则说明该区间中无未染色点。

 代码如下:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <iostream>
 4 #include <string>
 5 #include <math.h>
 6 #include <algorithm>
 7 #include <queue>
 8 #include <set>
 9 const int INF=0x3f3f3f3f;
10 using namespace std;
11 #define maxn 1000010
12 
13 struct node{
14     int l;
15     int r;
16     int num;
17 };
18 
19 int n,q;
20 int fa[maxn];
21 node a[maxn];
22 node tmp[maxn];
23 
24 int Find(int x)
25 {
26     return x==fa[x]?x:fa[x]=Find(fa[x]);
27 }
28 
29 bool cmp(node a,node b)
30 {
31     return a.num>b.num;
32 }
33 
34 bool judge(int tot)
35 {
36     for(int i=1;i<=n;i++)
37         fa[i]=i;
38     for(int i=1;i<=tot;i++)
39         tmp[i]=a[i];
40     sort(tmp+1,tmp+1+tot,cmp);
41     for(int i=1,j;i<=tot;i=j+1)
42     {
43         j=i;
44         int l=tmp[i].l;
45         int r=tmp[i].r;
46         int L=tmp[i].l;
47         int R=tmp[i].r;
48         while(j<tot&&tmp[j].num==tmp[j+1].num)
49         {
50             j++;
51             l=max(l,tmp[j].l);//取交集
52             r=min(r,tmp[j].r);
53             L=min(L,tmp[j].l);//取并集
54             R=max(R,tmp[j].r);
55         }
56         if(l>r||l>Find(r))//为空或无未染色点
57             return 0;
58         while(L<=R)
59         {
60             if(Find(R)==R)
61             {
62                 fa[R]=Find(L-1);//染色
63                 R--;
64             }
65             else
66                 R=fa[R];//直接跳转到其父节点
67         }
68     }
69     return 1;
70 }
71 
72 int main()
73 {
74     scanf("%d %d",&n,&q);
75     for(int i=1;i<=q;i++)
76     {
77         scanf("%d %d %d",&a[i].l,&a[i].r,&a[i].num);
78     }
79     int L=1;
80     int R=q;
81     int ans=0;
82     while(L<=R)
83     {
84         int mid=(L+R)/2;
85         if(judge(mid))
86             L=mid+1;
87         else
88         {
89             ans=mid;
90             R=mid-1;
91         }
92     }
93     printf("%d
",ans);
94     return 0;
95 }

 

 

 

原文地址:https://www.cnblogs.com/jiamian/p/11265547.html