P9828 & ICPC 2020 上海 J

题意

给定 \(n\) 个三元组,每个三元组定义了三个维度的区间。判断是否存在一个点 \((x, y, z)\),使得对于每个三元组,该点至少在一个维度的区间内。

题解

Cubber 和官解的做法太高级了,笔者看不懂。

这里提供一种小清新做法。

三个维度比较难做,考虑拍扁它,使其变成一个二维问题。

具体可以使用线段树分治来去掉第一维的限制,在线段树的节点挂上第一维不满足条件的三元组,然后他就变成一个二维问题了。

现在我们来思考如何做剩下的两个维度。

可以对第二维建线段树,维护两个值 \(mx[u],mn[u]\)

  • \(mx[u]\) :第三维必须满足 \(\ge\) \(mx[u]\)
  • \(mn[u]\) :第三维必须满足 \(\le\) \(mn[u]\)

当第二维度的值 \(b\) 不在三元组 \(i\) 的第二维度区间内时,为了满足该三元组,必须让第三维度的值 \(c\) 落在 \(i\) 的第三维度区间内。多个三元组的要求取交集。

具体怎么实现呢,我们在第二维度线段树上查询,从根开始,维护当前第三维度的可行区间 \([x,y]\) ,初始为 \([1,len[2]]\)

遍历时,用每个节点的 \(mx\)\(mn\) 来更新 \(x,y\) ,如果到达叶子且 \(x < y\),则找到了一个合法的第三维区间,结合前两维输出即可。

关于回溯版本,可以使用主席树,也可以直接搞个栈来记录更新操作。

时间复杂度 \(O(nlog^2 n)\)

代码

const int N = 2e5 + 10;
int n,tp,len[3],Mi[N][3],Mx[N][3],mi[N*4],mx[N*4];
std::pair<int,pii> s[N*32];
std::vector<int> num[3],coc[N*4];

void ins(int u,int l,int r,int x,int y,int i)
{
	if(x <= l && r <= y) return void(coc[u].push_back(i));
	int mid = l + r >> 1;
	if(x <= mid) ins(u*2,l,mid,x,y,i);
	if(y > mid) ins(u*2+1,mid+1,r,x,y,i);
}

void upd(int u,int l,int r,int x,int y,int mxx,int mnx)
{
	if(x <= l && r <= y) {s[++tp] = {u,{mx[u],mi[u]}};ckmax(mx[u],mxx); ckmin(mi[u],mnx);return;}
	int mid = l + r >> 1;
	if(x <= mid) upd(u*2,l,mid,x,y,mxx,mnx);
	if(y > mid) upd(u*2+1,mid+1,r,x,y,mxx,mnx);
}

void output(int u,int l,int r,int x,int y,int k)
{
	ckmax(x,mx[u]); ckmin(y,mi[u]); if(x > y) return;
	if(l == r){std::cout<<"YES\n"<<num[0][k-1]<<" "<<num[1][l-1]<<" "<<num[2][x-1]<<"\n";exit(0);}
	int mid = l + r >> 1; output(u*2,l,mid,x,y,k); output(u*2+1,mid+1,r,x,y,k);
}

void dfs(int u,int l,int r)
{
	int st = tp;
	for(int v : coc[u])
    {
		if(1 <= Mi[v][1]-1) upd(1,1,len[1],1,Mi[v][1]-1,Mi[v][2],Mx[v][2]);
		if(Mx[v][1]+1 <= len[1]) upd(1,1,len[1],Mx[v][1]+1,len[1],Mi[v][2],Mx[v][2]);
	}
	if(l == r) output(1,1,len[1],1,len[2],l);
	else {int mid = l + r >> 1; dfs(u*2,l,mid), dfs(u*2+1,mid+1,r);}
	while(tp != st){auto [x,y] = s[tp--]; mx[x] = y.fi; mi[x] = y.se;}
}

void solve()
{   
    std::cin >> n;
    memset(mi,0x3f,sizeof mi); 
    rep(i,1,n) rep(j,0,2) std::cin >> Mi[i][j] >> Mx[i][j];
    rep(j,0,2)
	{
		rep(i,1,n) {num[j].push_back(Mi[i][j]);num[j].push_back(Mx[i][j]);}
		sort(all(num[j])); num[j].erase(unique(all(num[j])),num[j].end()); len[j] = num[j].size();
		rep(i,1,n)
			Mi[i][j] = std::lower_bound(all(num[j]),Mi[i][j])-num[j].begin()+1,
			Mx[i][j] = std::lower_bound(all(num[j]),Mx[i][j])-num[j].begin()+1;
	}
	rep(i,1,n)
    {
		if(1 <= Mi[i][0]-1) ins(1,1,len[0],1,Mi[i][0]-1,i);
		if(len[0] >= Mx[i][0]+1) ins(1,1,len[0],Mx[i][0]+1,len[0],i);
	}
	dfs(1,1,len[0]); std::cout<<"NO\n";
}
posted @ 2026-01-10 18:51  Zheng_iii  阅读(14)  评论(0)    收藏  举报