题解 P2898 【[USACO08JAN]Haybale Guessing G】

题目链接

Solution [USACO08JAN]Haybale Guessing G

题目大意:给定长为(n)的序列,(q)次问答,每次给定([l,r])内的最小值为(v),求最早会与之前问答矛盾的问答

线段树,二分


分析:

首先答案是满足单调性的,如果在前(x)个问答相互矛盾,那前(x + 1)个问答也一定相互矛盾,因此可以二分答案

如果有两个问答([l_1,r_1,v],[l_2,r_2,v]),如果([l_1,r_1] cap[l_2,r_2]=emptyset),那么是相互矛盾的,因为序列内元素两两不同,否则我们可以确定(v)([l_1,r_1] cap[l_2,r_2])

如果有两个问答([l_1,r_1,v_1],[l_2,r_2,v_2])满足(v_1<v_2),且([l_1,r_1] subseteq[l_2,r_2])那么也是互相矛盾的

接下来我们按照(v)从大到小的顺序,考虑求交之后的问答。如果当前有问答([l,r,v]),那么以后的问答都不能将它们的(v)放在([l,r])内了,否则就互相矛盾

处理第一个限制:直接依次枚举即可

处理第二个限制:我们将问答按照(v)从小到大排序,那么我们只需要考虑之前加入的问答的区间中是否存在包含在当前问答的区间内的即可

对于所有左端点都为(x)的区间,我们保留右端点的最小值

当前区间为([l,r]),如果之前所有左端点(xin[l,r])的区间中,右端点的最小值(yin[l,r]),那么就有互相矛盾的问答

我们要处理的即为单点修改,区间求(min),线段树可以维护

处理第三个限制:按照(v)从大到小的顺序,考虑求交之后的回答。如果之前所有的区间将当前区间([l,r])全部覆盖了,那么存在矛盾

区间覆盖,查询一段区间是否全部被覆盖,再开一棵线段树即可

#include <cstdio>
#include <cctype>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 2e6 + 100;
inline int read(){
	int x = 0;char c = getchar();
	while(!isdigit(c))c = getchar();
	while(isdigit(c))x = x * 10 + c - '0',c = getchar();
	return x;
}
int n,q,ans;
struct Query{int l,r,v;}query[maxn];
struct Seg{
	int l,r;
	bool operator == (const Seg &rhs)const{
		return l == rhs.l && r == rhs.r;
	}
}seg[maxn];
inline Seg merge(Seg a,Seg b){
	if(!a.l)return b;
	if(max(a.l,b.l) > min(a.r,b.r))return Seg{0,0};
	return Seg{max(a.l,b.l),min(a.r,b.r)};
}
vector<Query> vec,tmp;
inline void discretize(){
	static int tmp[maxn];
	for(int i = 1;i <= q;i++)
		tmp[i] = query[i].v;
	sort(tmp + 1,tmp + 1 + q);
	int tot = unique(tmp + 1,tmp + 1 + q) - tmp - 1;
	for(int i = 1;i <= q;i++)
		query[i].v = lower_bound(tmp + 1,tmp + 1 + tot,query[i].v) - tmp;
}
namespace st1{
	int mark[maxn << 2];
	#define ls (rt << 1)
	#define rs (rt << 1 | 1)
	inline void build(int l = 1,int r = n,int rt = 1){
		mark[rt] = 0x7fffffff;
		if(l == r)return;
		int mid = (l + r) >> 1;
		build(l,mid,ls);
		build(mid + 1,r,rs);
	}
	inline void pushup(int rt){mark[rt] = min(mark[ls],mark[rs]);}
	inline void modify(int pos,int v,int l = 1,int r = n,int rt = 1){
		if(l == r){
			mark[rt] = min(mark[rt],v);
			return;
		}
		int mid = (l + r) >> 1;
		if(pos <= mid)modify(pos,v,l,mid,ls);
		else modify(pos,v,mid + 1,r,rs);
		pushup(rt);
	}
	inline int query(int a,int b,int l = 1,int r = n,int rt = 1){
		if(a <= l && b >= r)return mark[rt];
		int mid = (l + r) >> 1,res = 0x7fffffff;
		if(a <= mid)res = min(res,query(a,b,l,mid,ls));
		if(b >= mid + 1)res = min(res,query(a,b,mid + 1,r,rs));
		return res;
	}
	#undef ls
	#undef rs
}
namespace st2{
	#define ls (rt << 1)
	#define rs (rt << 1 | 1)
	int tr[maxn << 2];
	inline void pushup(int rt){tr[rt] = tr[ls] && tr[rs];}
	inline void pushdown(int rt){
		if(tr[rt])tr[ls] = tr[rs] = 1;
	}
	inline void build(int l = 1,int r = n,int rt = 1){
		tr[rt] = 0;
		if(l == r)return;
		int mid = (l + r) >> 1;
		build(l,mid,ls);
		build(mid + 1,r,rs);
	}
	inline void modify(int a,int b,int l = 1,int r = n,int rt = 1){
		if(a <= l && b >= r){
			tr[rt] = 1;
			return;
		}
		pushdown(rt);
		int mid = (l + r) >> 1;
		if(a <= mid)modify(a,b,l,mid,ls);
		if(b >= mid + 1)modify(a,b,mid + 1,r,rs);
		pushup(rt);
	}
	inline int query(int a,int b,int l = 1,int r = n,int rt = 1){
		if(a <= l && b >= r)return tr[rt];
		pushdown(rt);
		int mid = (l + r) >> 1,res = 1;
		if(a <= mid)res = res && query(a,b,l,mid,ls);
		if(b >= mid + 1)res = res && query(a,b,mid + 1,r,rs);
		return res;
	}
	#undef ls
	#undef rs
}
inline bool check(int limit){
	for(int i = 1;i <= q;i++)seg[i] = Seg{0,0};
	for(int i = 1;i <= limit;i++){
		int l = query[i].l,r = query[i].r,v = query[i].v;
		seg[v] = merge(seg[v],Seg{l,r});
		if(!seg[v].l)return true;
	}
	st1::build();
	vec.clear();
	tmp.clear();
	for(int i = 1;i <= limit;i++)vec.push_back(query[i]);
	sort(vec.begin(),vec.end(),[](Query a,Query b){return a.v < b.v;});
	for(int i = 0;i < vec.size();i++){
		if(i && vec[i].v != vec[i - 1].v){
			for(auto now : tmp)st1::modify(now.l,now.r);
			tmp.clear();
		}
		Query now = vec[i];
		if(st1::query(now.l,now.r) <= now.r)return true;
		tmp.push_back(vec[i]);
	}
	st2::build();
	for(int i = q;i >= 1;i--)
		if(seg[i].l){
			if(st2::query(seg[i].l,seg[i].r))return true;
			st2::modify(seg[i].l,seg[i].r);
		}
	return false;
}
int main(){
	n = read(),q = read();
	for(int i = 1;i <= q;i++)
		query[i].l = read(),query[i].r = read(),query[i].v = read();
	discretize();
	int l = 1,r = q,ans = 0;
	while(l <= r){
		int mid = (l + r) >> 1;
		if(check(mid))ans = mid,r = mid - 1;
		else l = mid + 1;
	}
	printf("%d
",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/colazcy/p/13785816.html