【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
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 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; } |
| 欢迎来原网站坐坐! >原文链接<
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 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 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架