平面二维点对问题(转化一维)
作者:互联网
【元素周期表】通过观察点对构造规律,转化成矛盾或者传递关系
平面坐标系内,给出p个点对(x,y),如果有3个同行或者同列的点对,那么他们组成的“矩形四个角”就都被覆盖,求最少添加多少点使得所有n*m区域都被覆盖。
部分分:p=0,考虑构造,发现只要靠边一行一列都填满就可以满足要求
正解:把横坐标看成一边的点对,纵坐标看成一边点对,如果(x,y)存在点,就连接x<-->y。发现对于矩形3点构成补成的1个点对连通性没影响,所以相当于求添加多少边使得所有1n和1m联通。ans=联通块数量-1
点击查看代码
#include<iostream>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<cstring>
#include<cstdlib>
#include<iomanip>
#include<algorithm>
#include<vector>
#include<deque>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define rint register int
#define _f(i,a,b) for(rint i=a;i<=b;++i)
#define f_(i,a,b) for(rint i=a;i>=b;--i)
#define chu printf
#define ll long long
#define INF 2147483647
inline ll re()
{
ll h=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')h=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*h;
}
struct node
{
int to,nxt;
}e[400000+100];
int head[400000+100],tot,vis[400000+10],ans;
inline void Add(int u,int v)
{
e[++tot].to=v;e[tot].nxt=head[u];head[u]=tot;
}
int n,m,q;
inline void dfs(int x)
{
vis[x]=1;
for(rint i=head[x];i;i=e[i].nxt)
{
int to=e[i].to;
if(vis[to])continue;
dfs(to);
}
}
int main()
{
//freopen("","r",stdin);
//freopen("","w",stdout);
n=re(),m=re(),q=re();
_f(i,1,q)
{
int r=re(),c=re();Add(r,c+n);Add(c+n,r);
}
_f(i,1,n+m)
if(!vis[i])++ans,dfs(i);
chu("%d",ans-1);
return 0;
}
/*
*/
【线段树区间操作】数据结构维护连续区间点对。质数合数修改分别维护。
【完美子图-馈赠3】a[x]=y,转换成求a的连续数值子串数量,用线段树+单调队列从左向右扫描累计\(Max[S]-Min[S]=R-L\)的区间个数
标签:ch,rint,ll,getchar,二维,一维,平面,include,define 来源: https://www.cnblogs.com/403caorong/p/16674041.html