【noi.ac #1770】B

题目

在一个 N×NN×N 的水池四周,有 4N4N 个人想要在这里钓鱼,他们围着水池站了一圈,水池四边每个格子都有一个人。

一个人在钓鱼的时候,他需要把钓竿垂直于他所在的水池边线放置,并且他的钓竿不能与其他人的钓竿有交叉。

每个人的钓竿长度不一定相同,但是有趣的是,处于同一边的人的钓竿长度是有序的,从左到右可能是升序,也可能是降序。同时,相对的两个人的鱼竿长度和是不超过 NN 的。

现在,他们想要知道最多能够允许多少人同时钓鱼。

输入格式
第一行一个整数 NN。

第二行 NN 个整数 a1,a2,⋯,ana1,a2,⋯,an,表示水池上边的人的钓竿长度,按照从左到右的顺序给出。

第三行 NN 个整数 b1,b2,⋯,bnb1,b2,⋯,bn,表示水池下边的人的钓竿长度,按照从左到右的顺序给出。

第四行 NN 个整数 c1,c2,⋯,cnc1,c2,⋯,cn,表示水池左边的人的钓竿长度,按照从上到下的顺序给出。

第五行 NN 个整数 d1,d2,⋯,dnd1,d2,⋯,dn,表示水池右边的人的钓竿长度,按照从上到下的顺序给出。

输出格式
一个整数,表示最多能同时钓鱼的人数。

样例
Input
2
1 1
1 1
1 1
1 1
Output
4
数据范围
10%的数据满足:N≤5N≤5
30%的数据满足:N≤10N≤10
60%的数据满足:N≤200N≤200
对于100%的数据满足:N≤10000,ai+bi≤N,ci+di≤NN≤10000,ai+bi≤N,ci+di≤N。

时间限制:1s1s
空间限制:256MB

思路

只有方向不同的可能会发生冲突,那么一个显然的想法就是把上下两边的放X集,左右两边的放Y集,然后如果会发生冲突就连一条边,那么答案就是 4N4N- 最大匹配。

但是这样边数太多。由于每一条边上的人都是有序的,所以对于一个人来说,会发生冲突的一定是一段连续的区间,所以可以使用线段树来优化连边。具体来说就是,对于左右两边的分别建立线段树,然后对线段树的边连 \infty 的边。对于上下的人,便找出发生冲突的区间对应的线段树上的节点,然后向那些节点连边。

点数 O(N)O(N),边数 O(NlogN)O(N\log{N})

代码

#include<bits/stdc++.h>
#define M 2400000
#define N 85536
#define inf 0x3f3f3f3f
using namespace std;
bool cmp(int x,int y){return y<x;}
int A[N],B[N],C[N],D[N],S,T,a[N],b[M],c[M],d[M],e[N],h[N],l,m,n,q[N],r,t,x;
bool check(int*X)
{
	for(int i=1; i<n; i++)if(X[i+1]<X[i])return 0;
	return 1;
}
void add(int u,int v,int w){b[++t]=a[u],c[a[u]=t]=v,d[t]=w,b[++t]=a[v],c[a[v]=t]=u;}
void add(int u,int v,int w,int s)
{
	for(u+=m-1,v+=m+1;u^v^1;u>>=1,v>>=1)
	{
		if(~u&1)add(w,s+(u^1),inf);
		if(v&1)add(w,s+(v^1),inf);
	}
}
bool bfs()
{
	memset(h+1,-1,T<<2),l=0,r=1;
	while(l<r)for(int u=q[l++],i=a[u]; i; i=b[i])if(d[i]&&!~h[c[i]])h[q[r++]=c[i]]=h[u]+1;
	return~h[T];
}
bool dfs(int u)
{
	if(u==T)return 1;
	for(int&i=e[u]; i; i=b[i])if(d[i]&&h[c[i]]==h[u]+1&&dfs(c[i]))return d[i]--,++d[i^1];
	return 0;
}
int main()
{
	for(scanf("%d",&n),m=t=1,x=n<<2;m<n+2;m<<=1);
	T=n+n+m+m+m+m-1;
	for(int i=1; i<=n; i++)scanf("%d",A+i);
	for(int i=1; i<=n; i++)scanf("%d",B+i),B[i]=n+1-B[i];
	for(int i=1; i<=n; i++)scanf("%d",C+i);
	for(int i=1; i<=n; i++)scanf("%d",D+i),D[i]=n+1-D[i];
	for(int i=1; i<m; i++)add(n+n+i,n+i<<1,inf),add(n+n+i,n+i<<1|1,inf),add(n+n+m+m-1+i,(n+m+i<<1)-1,inf),add(n+n+m+m-1+i,n+m+i<<1,inf);
	if(check(A))
	{
		for(int i=1; i<=n; i++)
		add(lower_bound(A+1,A+C[i]+1,i)-A,C[i],i,n+n);
		for(int i=1; i<=n; i++)
		add(lower_bound(A+D[i],A+n+1,i)-A,n,n+i,n+n);
	}
	else
	{
		for(int i=1; i<=n; i++)
		add(1,upper_bound(A+1,A+C[i]+1,i,cmp)-A-1,i,n+n);
		for(int i=1; i<=n; i++)
		add(D[i],upper_bound(A+D[i],A+n+1,i,cmp)-A-1,n+i,n+n);
	}
	if(check(B))
	{
		for(int i=1; i<=n; i++)add(1,upper_bound(B+1,B+C[i]+1,i)-B-1,i,n+n+m+m-1);
		for(int i=1; i<=n; i++)add(D[i],upper_bound(B+D[i],B+n+1,i)-B-1,n+i,n+n+m+m-1);
	}
	else
	{
		for(int i=1; i<=n; i++)add(lower_bound(B+1,B+C[i]+1,i,cmp)-B,C[i],i,n+n+m+m-1);
		for(int i=1; i<=n; i++)add(lower_bound(B+D[i],B+n+1,i,cmp)-B,n,n+i,n+n+m+m-1);
	}
	for(int i=1; i<=n; i++)add(S,i,1),add(S,n+i,1),add(n+n+m+i,T,1),add(n+n+m+m-1+m+i,T,1);
	while(bfs())for(memcpy(e,a,T+1<<2);dfs(S);x--);
	printf("%d\n",x);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章