QOJ 2266. Colorful Rectangle
QOJ 2266. Colorful Rectangle/SS250220A
题意
给定 \(n\) 个点,每个点有颜色 \(\in \{0,1,2\}\)。
求最小周长的矩形,使得矩形内部包含三种颜色的点。
\(n \le 10^5\)。
思路
考场想的分治做法。不会维护信息,所以获得 \(0 pts\)。
题解是偏序问题做法,我怎么没想偏序呢?

点的关系一共就这三种,从左到右标颜色 \(0,1,2\),其他情况都是旋转以及改变颜色排列得到的。
需要单 \(\log\) 的巨大常数做法。
考虑他们要满足什么偏序关系:
- \(x_0 < x_1 < x_2 \land y_1 < y_2 < y_0\)
 - \(x_0 \le x_1 \le x_2 \land y_0 \le y_1 \le y_2\)
 
因为是求最小值,所以你也可以认为所有 \(<\) 都是 \(\le\)。
第二种是好做的。
拆成两个不相干的二维偏序:\(x_0<x_1\land y_0<y_1,x_1<x_2\land y_1<y_2\)。扫描 \(x\) 这一维做,时间复杂度 \(O(n \log n)\)。
做第一种的话,求的东西不可差分。有 \(3\) 种颜色,考虑把其中两个颜色看做数据,第三种颜色看做询问。遇到数据时往询问贡献。遇到询问就单点查询。扫描需要先遇到数据再遇到询问。
不能单点修改,区间查询是因为询问如果弄两种颜色,无法在同一个时间访问到一组询问。
第二种情况不能使用一样的做法,是因为无法保证先遍历到数据再遍历询问,而且数据向询问贡献时,数据之间互不影响。
从小到大扫描 \(x\) 这一维。遇到 \(0,1\) 按照 \(2\) 的 \(y\) 为下标修改线段树等数据结构。遇到 \(2\) 就单点查询。
因为 \(0,1\) 除了 \(y\) 的偏序,\(x\) 也需要满足偏序关系,即需要满足 \(0\) 的时间戳在 \(1\) 之前。这个可以在线段树下放标记的时候处理一下下放的顺序。
具体地,线段树维护 \(0\) 的最小 \(-x+y\)(标记 \(0\)),\(1\) 的最小 \(-y\)(标记 \(1\)),以及最小的两个信息的和(标记 \(2\))。线段树任意节点的标记需要保证任意时刻标记 \(0\) 的时间戳小于标记 \(1\) 的,以及所有标记的时间戳均大于子节点标记的时间戳。
实现标记下放的方式是在下放标记 \(0\) 的时候,如果存在子节点标记 \(1\),就先把子节点的标记 \(1\) 放下去。其他没有什么难点了。
可能需要注意一下两点共水平线的情况有没有考虑到。题目保证不存在三个不同色点共水平线。
时间复杂度 \(O(n \log n)\)。
常数超级大。
code
#include<bits/stdc++.h>
#define sf scanf
#define pf printf
#define rep(x,y,z) for(int x=y;x<=z;x++)
#define per(x,y,z) for(int x=y;x>=z;x--)
using namespace std;
typedef long long ll;
namespace wing_heart {
	template<typename T>
	void _min(T &a,T b) { a=min(a,b); }
	constexpr int N=1e5+7,infint=0x7f7f7f7f;
	constexpr ll infll=0x3f3f3f3f3f3f3f3f;
	int n;
	struct node {
		int x,y,c;
	}a[N];
	int b[N],m;
	ll ans=infll;
	bool cmpx(node a,node b) { return a.x!=b.x? a.x < b.x: a.y<b.y; }
	struct mit {
		int tr[N];
		void clear() { memset(tr,0x7f,sizeof(tr)); }
		void add(int x,int val) { for(;x<=m;x+=x&-x) tr[x]=min(tr[x],val); }
		int query(int x) {
			int s=infint;
			for(;x;x-=x&-x) s=min(s,tr[x]);
			return s;
		}
	}T1[3][2];
	void solve1() {
		rep(i,0,2) rep(j,0,1) T1[i][j].clear();
		rep(i,1,n) b[i]=a[i].y;
		sort(b+1,b+n+1);
		m=unique(b+1,b+n+1)-b-1;
		sort(a+1,a+n+1,cmpx);
		rep(i,1,n) {	
			int x=a[i].x, y=a[i].y, c=a[i].c, _y=lower_bound(b+1,b+m+1,y)-b;
			int ne=(c+1)%3;
			int val=T1[c][0].query(_y);
			ans=min(ans,(1ll*T1[c][1].query(_y)+x+y)<<1ll);
			T1[ne][0].add(_y,-x-y);
			T1[ne][1].add(_y,val);
		}
	}
	struct seg {
		ll tag[N<<2][3];
		void clear() {
			memset(tag,0x3f,sizeof(tag));
		}
		void maketag(int u,int l,int r,ll val,int op) {
			if(op==1) _min(tag[u][1],val), _min(tag[u][2],tag[u][1]+tag[u][0]);
			else if(op==0) {
				if(l!=r && tag[u][1]!=infll)  {
					int mid=(l+r)>>1;
					maketag(u<<1,l,mid,tag[u][1],1), maketag(u<<1|1,mid+1,r,tag[u][1],1);
				}
				tag[u][1]=infll;
				_min(tag[u][0],val);
			} else _min(tag[u][2],val);
		}
		void pushdown(int u,int l,int r,int mid) {
			rep(op,0,2) if(tag[u][op]!=infll) maketag(u<<1,l,mid,tag[u][op],op), maketag(u<<1|1,mid+1,r,tag[u][op],op);
			memset(tag[u],0x3f,sizeof(tag[u]));
		}
		void change(int u,int l,int r,int L,int R,int val,int op) {
			if(l>=L && r<=R) return maketag(u,l,r,val,op);
			int mid=(l+r)>>1;
			pushdown(u,l,r,mid);
			if(L<=mid) change(u<<1,l,mid,L,R,val,op);
			if(mid+1<=R) change(u<<1|1,mid+1,r,L,R,val,op);
		}
		ll query(int u,int l,int r,int x) {
			if(l==r) return tag[u][2];
			int mid=(l+r)>>1;
			pushdown(u,l,r,mid);
			if(x<=mid) return query(u<<1,l,mid,x);
			return query(u<<1|1,mid+1,r,x);
		}
	}T2;
	void solve2() {
		rep(i,1,n) b[i]=a[i].y;
		sort(b+1,b+n+1);
		m=unique(b+1,b+n+1)-b-1;
		sort(a+1,a+n+1,cmpx);
		int t[3]={0,1,2};
		do {
			T2.clear();
			rep(i,1,n) {
				int x=a[i].x, y=a[i].y, c=a[i].c, _y=lower_bound(b+1,b+m+1,y)-b;
				if(c==t[0]) T2.change(1,1,m,1,_y,-x+y,0);
				else if(c==t[1]) T2.change(1,1,m,_y,m,-y,1);
				else ans=min(ans,(T2.query(1,1,m,_y)+x)<<1ll);
			}
		} while(next_permutation(t,t+3));
	}
    void main() {
		sf("%d",&n);
		rep(i,1,n) sf("%d%d%d",&a[i].x,&a[i].y,&a[i].c);
		solve1();
		solve2();
		rep(i,1,n) swap(a[i].x,a[i].y), a[i].y*=-1;
		solve1();
		solve2();
		rep(i,1,n) swap(a[i].x,a[i].y), a[i].y*=-1;
		solve1();
		solve2();
		rep(i,1,n) swap(a[i].x,a[i].y), a[i].y*=-1;
		solve1();
		solve2();
		pf("%lld\n",ans);
    }
}
int main() {
    #ifdef LOCAL
    freopen("my.out","w",stdout);
	#else 
	freopen("square.in","r",stdin);
	freopen("square.out","w",stdout);
    #endif
    wing_heart :: main();
}
本文来自博客园,作者:wing_heart,转载请注明原文链接:https://www.cnblogs.com/wingheart/p/18726657

                
            
        
浙公网安备 33010602011771号