博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
YYHS-猜数字(并查集/线段树维护)
阅读量:7081 次
发布时间:2019-06-28

本文共 2479 字,大约阅读时间需要 8 分钟。

题目描述

    LYK在玩猜数字游戏。

 

   总共有n个互不相同的正整数,LYK每次猜一段区间的最小值。形如[li,ri]这段区间的数字的最小值一定等于xi。

 

    我们总能构造出一种方案使得LYK满意。直到…… LYK自己猜的就是矛盾的!

 

    例如LYK猜[1,3]的最小值是2,[1,4]的最小值是3,这显然就是矛盾的。

 

    你需要告诉LYK,它第几次猜数字开始就已经矛盾了。

 

 

 

输入

    第一行两个数n和T,表示有n个数字,LYK猜了T次。
    接下来T行,每行三个数分别表示li,ri和xi。

 

 

 

输出

输出一个数表示第几次开始出现矛盾,如果一直没出现矛盾输出T+1。

 

样例输入

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

样例输出

3

提示

数据范围
对于50%的数据n<=8,T<=10。
 
对于80%的数据n<=1000,T<=1000。
对于100%的数据1<=n,T<=1000000,1<=li<=ri<=n,1<=xi<=n(但并不保证一开始的所有数都是1~n的)
 

 

Hint
 
建议使用读入优化
inline int read()
{
       int x = 0, f = 1;
 
       char ch = getchar();
       for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
 
       for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
 
       return x * f;
 
}

 

题解

这道题我们先考虑矛盾的情况

我们不难发现有以下两种情况是矛盾的

1.当一个区间覆盖了另一个区间且大的区间的x值比另一个区间的x值小的时候是矛盾的

2.当两个区间的x值相同时,如果这两个区间没有交集,这也是矛盾的

知道了矛盾的情况后

我们可以二分矛盾的句子的位置

将前k个句子按x值从大到小排个序,然后我们枚举,判断当前区间的x值和前一个区间的x值是否相同

如果相同,就判断一下有没有交集

如果不相同,我们可以维护一个线段树,将交集的区间覆盖为1,查询并集的区间是否被覆盖为1,当然我们也可以用并查集来维护,我是用并查集来做的,但还是感觉线段树应该好懂一些(虽然代码长了些)

1 #include
2 #define N 1000005 3 using namespace std; 4 int n,T,cnt; 5 int fa[N]; 6 struct node{ 7 int l,r,x; 8 }a[N],b[N]; 9 bool cmp(node x,node y){ return x.x>y.x; }10 int find(int x){ if (x!=fa[x]) fa[x]=find(fa[x]); return fa[x]; }11 bool check(int x){12 int f1,f2;13 for (int i=1;i<=n+1;i++) fa[i]=i;14 for (int i=1;i<=x;i++) b[i]=a[i];15 sort(b+1,b+1+x,cmp);16 int lmin=b[1].l,lmax=b[1].l,rmin=b[1].r,rmax=b[1].r;17 for (int i=2;i<=x;i++){18 if (b[i].x
rmin) return true;//判断是否有大于b[i].x的区间覆盖了 21 f2=find(rmax+1);22 for (int j=find(lmin);j<=rmax;j++){23 f1=find(j);24 fa[f1]=f2;25 }26 lmin=lmax=b[i].l;27 rmin=rmax=b[i].r;28 } else{29 lmin=min(lmin,b[i].l);30 lmax=max(lmax,b[i].l);31 rmin=min(rmin,b[i].r);32 rmax=max(rmax,b[i].r);33 if (lmax>rmin) return true;//判断是否有交集 34 }35 }36 f1=find(lmax);37 if (f1>rmin) return true;38 return false;39 }40 int main(){41 scanf("%d%d",&n,&T);42 for (int i=1;i<=T;i++)43 scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].x);44 int l=1,r=T;45 int ans=T+1;46 while (l<=r){47 int mid=(l+r)>>1;48 if (check(mid)){49 ans=mid;50 r=mid-1;51 } else l=mid+1;52 }53 printf("%d\n",ans);54 return 0;55 }
View Code

 

转载于:https://www.cnblogs.com/zhuchenrui/p/7767178.html

你可能感兴趣的文章
express不是内部或外部命令
查看>>
通过反射获取成员方法并使用
查看>>
String StringBuffer StringBuilder
查看>>
bash的工作特性及命令状态返回查询
查看>>
Samba服务共享(匿名用户访问、本地用户访问、虚拟用户访问)
查看>>
HttpServletResponse输出乱码的问题
查看>>
你真的很熟分布式和事务吗?
查看>>
基于ThreadPoolExecutor实现工作引擎参考
查看>>
Go语言的基本数据类型
查看>>
WEB测试:***apache
查看>>
42 个移动端启动页面优化 Tips
查看>>
Egret之ProtoBuf安装
查看>>
Cocos2d-x3.0游戏实例《别救我》目录
查看>>
我的友情链接
查看>>
ASP开发中数据库文件调用的捷径
查看>>
debian启动项与服务设置
查看>>
WinPcap编程环境设置
查看>>
基于openssl的https服务配置
查看>>
从 CentOS 5.5 中精简出属于自己的专属Linux (三)
查看>>
C和指针---第十五章:输入/输出函数
查看>>