1. 程式人生 > 其它 >【題解】[JOISC2020] 美味しい美味しいハンバーグ

【題解】[JOISC2020] 美味しい美味しいハンバーグ

\(K\) 非常小,先找特殊性質。

首先 \(K=1\) 的時候直接求交集即可。

對於 \(K=2\) ,先考慮固定第一個點。我們令左的右邊界為 \(x\) ,那麼第一個點的橫座標為 \(x\) 一定最優。因為如果橫座標 \(>x\) ,一定會漏掉某個矩形,如果 \(<x\) ,而不存在右端點 \(<x\) 的,所以選則 \(x\) 一定最優。

同理我們找到最右的左邊界,最上的下邊界和最下的上邊界。那麼一定選擇這些邊界上的點最優。

對於 \(K\le 3\) 的情況,我們只有三個點卻要覆蓋四個邊界,那麼只能選擇邊界的交點。而交點只有 \(4\) 個,所以我們直接暴搜即可。時間複雜度 \(\mathcal{O}(4^KN)\)

對於 \(K=4\) 還有一種情況是四個邊界每個邊界上恰好一個點。

那麼對於每個矩形。一定與某些邊界有交集,且不可能與四個同時

如果至少與四個邊界中的三個有交集,那麼一定包含一條邊界,這類矩形可以忽略。

如果與四個邊界中的一個有交集,那麼這個邊界上的點一定在交集內。

否則會與四個邊界中的兩個有交集,我們令兩個交集為 \([l_1,r_1]\)\([l_2,r_2]\) ,那麼兩個中至少選擇一個,經典 2-SAT 問題,直接建圖跑即可。

時間複雜度 \(\mathcal{ O}(4^KN+N\log N)\)

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define pre(i,a,b) for(int i=a;i>=b;i--)
#define N 200005
#define M 2000005
using namespace std;
const int inf = 0x7fffffff;
int n,k,v[N],idx;
struct node{int l,r,u,d;}a[N];
struct pt{
	int x,y;
	pt(int X=0,int Y=0){x=X,y=Y;}
}sta[5],lim[4];
bool ck(node x,pt y){return x.l<=y.x&&y.x<=x.r&&x.d<=y.y&&y.y<=x.u;}
pt ad(pt x,pt y){return pt(max(x.x,y.x),min(x.y,y.y));}
struct seg{
	int l,r,op;
	seg(int L=0,int R=0,int O=0){l=L,r=R,op=O;}
};
vector<seg>c[4];
int h[M],tot,f[N];
struct edge{int to,nxt;}e[M<<1];
void add(int x,int y){e[++tot].nxt=h[x];h[x]=tot;e[tot].to=y;}
int rev(int x){if(x>n*2)return x-n*2;return x+n*2;}
void calc(int l,int r,int d,int u,node x){
	int sum=0;pt p,q;int opx=~0,opy=~0;
	if(x.l<=l&&l<=x.r)q=pt(x.d,x.u),opy=0,swap(p,q),swap(opx,opy),sum++;
	if(x.l<=r&&r<=x.r)q=pt(x.d,x.u),opy=1,swap(p,q),swap(opx,opy),sum++;
	if(x.d<=d&&d<=x.u)q=pt(x.l,x.r),opy=2,swap(p,q),swap(opx,opy),sum++;
	if(x.d<=u&&u<=x.u)q=pt(x.l,x.r),opy=3,swap(p,q),swap(opx,opy),sum++;
	if(sum>=3)return;
	if(sum==1)lim[opx]=ad(lim[opx],p);
	if(sum==2){
		c[opx].push_back(seg(p.x,p.y,++idx));
		c[opy].push_back(seg(q.x,q.y,++idx));
		add(rev(idx-1),idx);add(rev(idx),idx-1);
	}
}
bool cmp1(seg x,seg y){return x.r<y.r;}
bool cmp2(seg x,seg y){return x.l<y.l;}
int dfn[M],st[M],top,cnt,cc,low[M],mat[M],vis[M];
void tar(int x){
	dfn[x]=low[x]=++cc;vis[st[++top]=x]=1;
	for(int i=h[x];i;i=e[i].nxt){
		if(!dfn[e[i].to])tar(e[i].to),low[x]=min(low[x],low[e[i].to]);
		else if(vis[e[i].to])low[x]=min(low[x],dfn[e[i].to]);
	}
	if(dfn[x]==low[x]){
		++cnt;
		while(true){
			int y=st[top--];
			vis[y]=0;mat[y]=cnt;
			if(x==y)return;
		}
	}
}
void solve(){
	int l=~0,r=inf,u=inf,d=~0;
	rep(i,1,n)l=max(l,a[i].l),r=min(r,a[i].r),u=min(u,a[i].u),d=max(d,a[i].d);
	rep(i,0,3)lim[i]=pt(0,inf);rep(i,1,n)calc(r,l,u,d,a[i]);
	idx+=2*n;
	rep(op,0,3){
		sort(c[op].begin(),c[op].end(),cmp1);
		int sz=c[op].size();
		for(int i=0;i<sz;i++){
			if(c[op][i].r<lim[op].x||c[op][i].l>lim[op].y)
				add(c[op][i].op,rev(c[op][i].op));
			f[i]=++idx;add(f[i],rev(c[op][i].op));
			if(i>0)add(f[i],f[i-1]);
			int l=0,r=i-1,ed=~0;
			while(l<=r){
				int mid=(l+r)>>1;
				if(c[op][mid].r<c[op][i].l)ed=mid,l=mid+1;
				else r=mid-1;
			}
			if(~ed)add(c[op][i].op,f[ed]);
		}
		sort(c[op].begin(),c[op].end(),cmp2);
		for(int i=sz-1;i>=0;i--){
			f[i]=++idx;add(f[i],rev(c[op][i].op));
			if(i<sz-1)add(f[i],f[i+1]);
			int l=i+1,r=sz-1,ed=~0;
			while(l<=r){
				int mid=(l+r)>>1;
				if(c[op][mid].l>c[op][i].r)ed=mid,r=mid-1;
				else l=mid+1;
			}
			if(~ed)add(c[op][i].op,f[ed]);
		}
	}
	memset(v,0,sizeof(v));
	rep(i,1,idx)if(!dfn[i])tar(i);
	rep(op,0,3){
		for(int i=0;i<(int)c[op].size();i++){
			int x=c[op][i].op,y=rev(x);
			if(mat[x]<mat[y])lim[op]=ad(lim[op],pt(c[op][i].l,c[op][i].r));
		}
	}
	printf("%d %d\n",r,lim[0].x);
	printf("%d %d\n",l,lim[1].x);
	printf("%d %d\n",lim[2].x,u);
	printf("%d %d\n",lim[3].x,d);
}
bool dfs(int x){
	vector<int>is;
	int l=~0,r=inf,u=inf,d=~0;
	rep(i,1,n)if(!v[i])
		l=max(l,a[i].l),r=min(r,a[i].r),u=min(u,a[i].u),d=max(d,a[i].d);
	if(-1==l){
		if(x==k+1){
			rep(i,1,k)printf("%d %d\n",sta[i].x,sta[i].y);
			return true;
		}
		sta[x]=pt(0,0);
	}
	if(x>k)return false;
	// type = 1  (l,u)
	pt cur=pt(l,u);sta[x]=cur;
	rep(i,1,n)if(!v[i]&&ck(a[i],cur))is.push_back(i),v[i]=1;
	if(dfs(x+1))return true;
	for(int i=0;i<(int)is.size();i++)v[is[i]]=0;is.clear();
	// type = 2  (l,d)
	cur=pt(l,d);sta[x]=cur;
	rep(i,1,n)if(!v[i]&&ck(a[i],cur))is.push_back(i),v[i]=1;
	if(dfs(x+1))return true;
	for(int i=0;i<(int)is.size();i++)v[is[i]]=0;is.clear();
	// type = 3  (r,u)
	cur=pt(r,u);sta[x]=cur;
	rep(i,1,n)if(!v[i]&&ck(a[i],cur))is.push_back(i),v[i]=1;
	if(dfs(x+1))return true;
	for(int i=0;i<(int)is.size();i++)v[is[i]]=0;is.clear();
	// type = 4  (r,d)
	cur=pt(r,d);sta[x]=cur;
	rep(i,1,n)if(!v[i]&&ck(a[i],cur))is.push_back(i),v[i]=1;
	if(dfs(x+1))return true;
	for(int i=0;i<(int)is.size();i++)v[is[i]]=0;is.clear();
	return false;
}
int main(){
	//freopen("08-14.in","r",stdin);
	freopen("INPUT","r",stdin);
	scanf("%d%d",&n,&k);
	rep(i,1,n)scanf("%d%d%d%d",&a[i].l,&a[i].d,&a[i].r,&a[i].u);
	if(!dfs(1))solve();
	return 0;
}