usaco 猜数游戏
2013-10-23 07:08
239 查看
Description
为了提高智商,锻炼思维能力,奶牛设计了一个猜数游戏。游戏开始前,贝西会在牛棚后面摆上N个数字。所有数字排成一条直线,按次序从1到N编号。每个数字在1到10^9之间,没有两个数字是一样的。游戏开始后,其他奶牛将会轮流询问贝西Q个问题,每个问题的格式都是一样的:
“位置在Ql到Qr的数字中,最小的数字是多少?”
对每个问题,贝西都会回答一个数字A,不过,她的回答可能是不正确的。请你帮助其他奶牛判断一下,贝西从哪里开始已经出现矛盾了。
Input Format
第一行:两个用空格分开的整数:N和Q,1 ≤ N ≤ 106,1 ≤ Q ≤ 25000第二行到第Q + 1行:每行三个用空格分开的整数,Ql,Qr和A,表示一个查询,1 ≤ Ql ≤ Qh ≤ N
Output Format
第一行:如果完全没有矛盾,输出0,否则输出最先造成矛盾的查询编号------------------------------------------------------------------
正解 = 找规律+并查集
Orz 神大胖指导。
正如题目所说,这 n 个数中不会有重复的,
因此对于相同的值的询问如果不存在交集便是一个矛盾,
如果存在交集,那这个数必然就在这个区间中,
但如果之前的询问已覆盖了这个区间
A:如果询问值比该数小,这是种合法情况,
因为之前的询问还能覆盖该区间外的地方,
B:如果询问值比该数大,显然矛盾.
得到一个判断一段查询是否合法的算法:
将所给的询问按数值排序(从大到小),
对于同个数值进行合并操作,
如不存在交集 =>存在矛盾
否则对询问交集中是否已被在比该数值大的值所覆盖,
由于已经按从小到大排过序,如果交集中有值必然比该数值大
所以,如果区间中不存在未覆盖的位置 = > 存在矛盾
否则说明至此未产生矛盾:
对于该同数值的询问的并集中未覆盖的部分进行覆盖
如果进行完所有操作未发现矛盾,则该区间不存在矛盾.
由于仅对区间中的未覆盖的位置进行查询及修改,可以用并查集进行加速.
在上述算法的基础上,我们可以对矛盾区间进行二分查找,不难得到答案.
Ps.笔者打的递归并查集爆(W)栈(T)了(F),不能忍,该模拟栈了- =.
代码如下:
#include<cstring> #include<algorithm> #include<cstdio> #include<string> #include<iostream> #include<queue> #define INF 99999999 #define min(X,Y) if(X>Y) X=Y #define max(X,Y) if(X<Y) X=Y #define N 1000122 #define M 25022 using namespace std; int f ,n,Q,mid,ans; int q ; struct Query{ int l,r,v; }a[M],b[M]; bool cmp(const Query&X,const Query&Y){ return X.v>Y.v; } int find(int now){ int tail=0; q[++tail]=now; while(1){ now=q[tail]; if(now==f[now]) break; q[++tail]=f[now]; } while(tail) f[q[tail--]]=now; return now; } bool check(){ for(int i=1;i<=n+3;i++) f[i]=i; memcpy(b,a,sizeof(Query)*(mid+1)); sort(b+1,b+1+mid,cmp); for(int i=1;i<=mid;i++){ int Min=b[i].l,Max=b[i].r; int L=b[i].l ,R=b[i].r; for(;i<=mid&&b[i].v==b[i+1].v;){ ++i; min(Min,b[i].l); max(Max,b[i].r); if(L>b[i].r||R<b[i].l) return false ; max(L,b[i].l); min(R,b[i].r); } if(find(L)>R) return false ; for(int k=find(Min);k<=Max;k=f[k]) f[k]=find(k+1); } return true; } int main(){ scanf("%d%d",&n,&Q); for(int i=1;i<=Q;i++) scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].v); int Le=1,Ri=Q; while(Ri>=Le){ mid=(Le+Ri)>>1; if(!check()){ Ri=mid-1; ans=mid; } else Le=mid+1; } printf("%d",ans); }
View Code
相关文章推荐
- BZOJ1594: [Usaco2008 Jan]猜数游戏
- bzoj 1594: [Usaco2008 Jan]猜数游戏【二分+线段树】
- [bzoj1594] [Usaco2008 Jan]猜数游戏
- bzoj 1594: [Usaco2008 Jan]猜数游戏——二分+线段树
- 1594: [Usaco2008 Jan]猜数游戏
- 【BZOJ1594】[Usaco2008 Jan]猜数游戏 二分答案+并查集
- 【bzoj2017】[Usaco2009 Nov]硬币游戏
- java猜数游戏
- 【BZOJ】1666: [Usaco2006 Oct]Another Cow Number Game 奶牛的数字游戏(刷水严重)
- BZOJ1610: [Usaco2008 Feb]Line连线游戏
- 博弈论+dp——洛谷P2964 [USACO09NOV]硬币的游戏A Coin Game
- C++一个猜数游戏程序
- 简单的猜数游戏
- 51nod 1536 不一样的猜数游戏
- BZOJ1610: [Usaco2008 Feb]Line连线游戏
- Java课程设计 猜数游戏个人博客
- 51NOD 1536 不一样的猜数游戏 数论
- 猜数游戏
- 【BZOJ1915】[Usaco2010 Open]奶牛的跳格子游戏 DP+单调队列
- bzoj 2017: [Usaco2009 Nov]硬币游戏【dp】