【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。。
代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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\n",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 }
同样是并查集为啥我的就那么慢。。TAT。。。
2016-10-28 14:48:53