首页 > 其他分享 >P2898 [USACO08JAN] Haybale Guessing G 题解

P2898 [USACO08JAN] Haybale Guessing G 题解

时间:2024-09-18 14:36:23浏览次数:8  
标签:USACO08JAN 覆盖 int 题解 Haybale 区间 return find lx

并查集好题

首先我们知道并查集是可以维护一个区间的覆盖问题的,具体操作就是,对于一个区间,我们让所有的点都有一个指针,这个指针指向这个区间的右端点+1(具体操作可以每个点指向右边,这样后面我们查到一个点的时候用路径压缩就可以了,能从\(\Theta(nlogn)\)变成\(\Theta(n)\) ),这样我们可以让整个区间都以此点为代表元。当查到某个点时,我们用路径压缩(前面说了为什么要用路径压缩)的find,就可以找到这个区间的右端点(即这个点右边被覆盖的最远的点),如果这个点大于等于当前我们要查有没有被覆盖的的区间的右端点,那么这个区间被覆盖了。

那么我们就可以做这道题了。

由于没有修改,自然想到可以离线下来,暴力二分去找第一个不符合的。
考虑如何判断当前问题是否矛盾。

首先我们来分析一下不合法的有哪几种情况:

一、如果两个区间的最小值相等,但没有交集。
二、如果一个小的区间被大的区间覆盖了。

什么意思呢,首先我们观察到题目说没有相等的数,于是我们可以肯定对于两个不相交的区间没有相同的最小值。然后,如果一个最小值较大的区间里有一段的最小值比他还小,那么不合法。读者可以自己想想是不是这两种情况涵括了所有不合法的可能。

因此我们很自然地想到(因为在相等区间内判断交集是否为空,在不等区间内判断大的是否包含小的,只和大小有关,而跟具体数值无关,也就是说我们只需要大小关系),可以把mid之前的所有询问从大到小排个序,对于每个区间:
1.如果和之前的区间值相等,那么判断交集是否为空。
2.如果和之前的不等(说明这个区间的值肯定比前面的要小),判断这个区间所在区间是否被前面的区间包含了。

注意:对于所有值的区间,覆盖关系就这样抽离,变得跟值没有关系了,所以我们才可以共用一个并查集。

还有就是程序实现逻辑可能和我们思考的顺序略有差别,这个请看下文。
其次你会发现只有每个值相同的区间求了交集,并且对区间内所有点进行覆盖(及开头说的那些操作),我们才能很方便的求出是否被前面的区间覆盖,一环套一环。
两个小小的问题:如果和之前的区间相等,怎么求交集呢?如果和之前的区间值不等,我们怎么判断包含呢?
一、我们可以维护\(lx\),\(ln\),\(rx\),\(rn\),\(p\)分别表示最大/最小的左端点,最大/最小的右端点,当前值,然后就可以方便求并集。
判断交集是否为空自然就是\(lx\)是否大于\(rn\)。
二、对于不同值的区间,可能要稍微麻烦一点,我们需要把这个区间全部找完才能判断和更新覆盖,所以这一部分,我们要放到这个值后面一个值时滞后操作。同时呢,我们在值不同的时候还要更新\(lx\),\(ln\),\(rx\),\(rn\),\(p\),这样才能构成一个逻辑闭环。
所以我们在总结出程序逻辑下的操作:对于所有值相同的区间,即
相等时:求并集,更新四个值,并查一下是否合法。以下简记为操作一。
不等时:查一下这个值的上一个值是否被覆盖,然后对上一个值的所有区间进行覆盖,再更新五个值(这次更新就让当前值成为下一轮的操作对象了)。以下简记为操作二。
举个例子:
image

代码:

#include<bits/stdc++.h>
using namespace std;
int n,q,fa[1000005],l,r,mid,ln,lx,rn,rx,p;
struct Quest{
	int ls,rs,x,id;
}co[25005],qu[25005];
int find(int x){
	if(fa[x]==x) return x;
	else return fa[x]=find(fa[x]);
}
bool cmp(Quest a,Quest b){
	return a.x>b.x;
}
bool check(int x){
	for(int i=1;i<=x;++i) qu[i]=co[i];
	sort(qu+1,qu+x+1,cmp);
	ln=lx=qu[1].ls,rn=rx=qu[1].rs,p=qu[1].x;
	for(int i=1;i<=n+1;++i) fa[i]=i; 
	for(int i=2;i<=x;++i){
		if(qu[i].x==p){
			ln=min(qu[i].ls,ln);
			lx=max(qu[i].ls,lx);
			rn=min(qu[i].rs,rn);
			rx=max(qu[i].rs,rx);
			if(lx>rn) return false;
		}
		else{
			if(find(lx)>rn) return false;
			for(int j=find(ln);;j=find(j+1))
				if(j>rx) break;
				else fa[j]=fa[j+1];
			p=qu[i].x;
			lx=ln=qu[i].ls;
			rx=rn=qu[i].rs;
		}
	}
	return find(lx)<=rn;
}
int main(){
	scanf("%d %d",&n,&q);
	for(int i=1;i<=q;++i) scanf("%d %d %d",&co[i].ls,&co[i].rs,&co[i].x);
	l=0,r=q+1;
	while(l<r){
		mid=(l+r)>>1;
		if(check(mid)) l=mid+1;
		else r=mid;
	}
	if(r==q+1) printf("0");
	else printf("%d",l);
	return 0;
}

这道题好的原因不仅是思路巧妙,更因为这是一种并查集的经典用法,建议学并查集的好好思考。

标签:USACO08JAN,覆盖,int,题解,Haybale,区间,return,find,lx
From: https://www.cnblogs.com/mountzhu/p/18418454

相关文章

  • 洛谷P8774 [蓝桥杯 2022 省 A] 爬树的甲壳虫 题解 期望DP
    题目链接:https://www.luogu.com.cn/problem/P8774思路:设\(f_i\)为甲壳虫从高度\(i\)到达高度\(n\)因为从高度\(i\)走\(1\)步有\(1-P_{i+1}\)的概率到达高度\(i+1\),有\(P_{i+1}\)的概率到达高度\(0\),所以:\(f_i=1+(1-P_{i+1})\timesf_{i+1}+P_{i+1}\times......
  • 洛谷P4550 收集邮票 题解 期望DP
    题目链接:https://www.luogu.com.cn/problem/P4550解题思路:定义状态\(f_i\)表示目前已经取到\(i\)种邮票的情况下,取完所有\(n\)很明显,\(f_n=0\),因为此时已经取完了\(n\)如果当前已经取到了\(i\)有\(\frac{i}{n}\)的概率取到现有的邮票(此时仍然拥有\(i\)有\(1-\frac{i......
  • 2024 CCPC 网赛题解
    G最大流#include<queue>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#defineMAXN205#defineINF0x3f3f3f3f3f3f3f3f#defineLLlonglong#defineIntregisterintusingnamespacestd;inlinevo......
  • 洛阳师范学院 ACM实验室 中秋娱乐赛“月饼代码大逃杀”题解
    题解包括C和C++两种语言_壹我要洋人死!1、直接输出即可C语言题解:#include<stdio.h>intmain(){printf("woyaoyangrensi!");return0;}C++语言题解:#include<iostream>usingnamespacestd;intmain(){ printf("woyaoyangrensi!"); return0;}......
  • P11072 Alice and Bob 题解
    简单博弈题。先说结论,如果存在\(a_i=0\)使得\(1\lei\lea_1\)的话,那么先手必胜,否则后手必胜。若满足上述条件显然先手必胜,将\(0\)搞到第一个就行。否则Alice每操作一次,如果操作后满足了上述条件,那么Bob赢,否则Bob只要不动就行。但是下一轮Alice必须动,要不然两......
  • 【洛谷 P1048】[NOIP2005 普及组] 采药 题解(动态规划+01背包)
    [NOIP2005普及组]采药题目描述辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株......
  • 历年CSP-J初赛真题解析 | 2019年CSP-J初赛阅读程序(16-33)
    学习C++从娃娃抓起!记录下CSP-J备考学习过程中的题目,记录每一个瞬间。附上汇总贴:历年CSP-J初赛真题解析|汇总_热爱编程的通信人的博客-CSDN博客#include<cstdio>#include<cstring>usingnamespacestd;charst[100];intmain(){scanf("%s",st);intn......
  • 【架构设计】多级缓存:应用案例与问题解决策略
    【架构设计】多级缓存:应用案例与问题解决策略多级缓存系统的工作原理及其在提升应用性能方面的关键作用。通过对比本地缓存与分布式缓存的特点| 原创作者/编辑:凯哥Java                    | 分类:架构设计系列教程多级缓存系统:提升性能的......
  • 【架构设计】多级缓存:应用案例与问题解决策略
      【架构设计】多级缓存:应用案例与问题解决策略 多级缓存系统的工作原理及其在提升应用性能方面的关键作用。通过对比本地缓存与分布式缓存的特点 | 原创作者/编辑:凯哥Java                    | 分类:架构设计系列教程 ......
  • 题解 CF993E 【Nikita and Order Statistics】
    初看这道题,以为又是什么数据结构数数题,没啥思路,结果推式子时搞出了一个类似可以卷积的玩意儿,所以果断\(FFT\)解决。那我们来分析问题:这道题里,值域没用,每一个数只要管它与\(x\)的相对大小关系即可。如果它小于\(x\)那么有贡献,赋值为一,否则为零。然后,可以求前缀和,区间部分......