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";
}

浙公网安备 33010602011771号