题意:有一个数轴,若干人在某个时刻开始从某个点朝某个方向按111的速度走若干时间。已知nnn个条件,形如tit_iti时刻xix_ixi的位置有人,求最少可能的人数。
∑n≤5×105\sum n\leq 5\times 10^5∑n≤5×105
画出 x−tx-tx−t二维平面,可以看成用最少k=±1k=\pm1k=±1的直线覆盖给出的nnn个点
转45°45\degree45°看成水平线或竖直线(但好像没啥区别)
过每个点作水平线和竖直线,将直线去重,然后直线建成点,点建成过它作的两个直线之间连的边,跑最小点覆盖即可。
注意匈牙利是O(nm)O(nm)O(nm),dinic只有O(mn)O(m\sqrt n)O(mn)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#define MAXN 200005
#define MAXM 400005
#define INF 0x3f3f3f3f
using namespace std;
struct edge{int u,v,c;}e[MAXM];
int head[MAXN],nxt[MAXM],cnt;
void ins(int u,int v,int c)
{e[++cnt]=(edge){u,v,c};nxt[cnt]=head[u];head[u]=cnt;
}
void addnode(int u,int v,int c){ins(u,v,c);ins(v,u,0);}
int s,t;
int dis[MAXN];
bool bfs()
{queue<int> q;q.push(s);memset(dis,-1,sizeof(dis));dis[s]=0;while (!q.empty()){int u=q.front();q.pop();for (int i=head[u];i;i=nxt[i])if (e[i].c&&dis[e[i].v]==-1){dis[e[i].v]=dis[u]+1;q.push(e[i].v);if (e[i].v==t)return true;}}return false;
}
int dfs(int u,int f)
{if (u==t||!f)return f;int used=0;for (int i=head[u];i;i=nxt[i])if (e[i].c&&dis[e[i].v]==dis[u]+1){int w=dfs(e[i].v,min(e[i].c,f));if (!w)continue;used+=w;e[i].c-=w;e[i^1].c+=w;f-=w;if (used==0)break;}if (!used) dis[u]=-1;return used;
}
int dinic()
{int mflow=0;while (bfs())mflow+=dfs(s,INF);return mflow;
}
int x[MAXN],y[MAXN],xl[MAXN],yl[MAXN],xcnt,ycnt;
int main()
{int T;scanf("%d",&T);while (T--){int n;scanf("%d",&n);for (int i=1;i<=xcnt+ycnt+2;i++) head[i]=0;for (int i=1;i<=cnt;i++) nxt[i]=0;cnt=1,xcnt=ycnt=0;for (int i=1;i<=n;i++){int a,b;scanf("%d%d",&a,&b);x[i]=xl[i]=a+b;y[i]=yl[i]=a-b;}sort(xl+1,xl+n+1);xcnt=unique(xl+1,xl+n+1)-xl-1;sort(yl+1,yl+n+1);ycnt=unique(yl+1,yl+n+1)-yl-1;s=xcnt+ycnt+1,t=s+1;for (int i=1;i<=xcnt;i++) addnode(s,i,1);for (int i=xcnt+1;i<=xcnt+ycnt;i++) addnode(i,t,1);for (int i=1;i<=n;i++){x[i]=lower_bound(xl+1,xl+xcnt+1,x[i])-xl;y[i]=lower_bound(yl+1,yl+ycnt+1,y[i])-yl;addnode(x[i],y[i]+xcnt,1);}printf("%d\n",dinic());}return 0;
}