Description
N*M的矩阵里面有k对不同颜色的点,同颜色的点之间互相连边,问所有的边是否能不相交
k
≤
1
0
5
k\le10^5
k≤105
Solution
首先因为边是可以随便拉扯的,因此很容易想到不合法的情况当且仅当两对点都在边界上,并且且它们相交
考虑把一条边拆成两个点,我们按照顺时针方向依次遍历这些点。一条边中的第一次出现的点入栈,第二次出现就出栈。那么不合法的情况就是一条边已经出栈了,它的两个点之间仍有未出栈的点。
一个比较牛逼的做法就是我们给每条边随机一个权值,那么就可以用前缀异或和来搞定这个“是否所有数字出现了恰好两次”的问题了
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)
#define fi first
#define se second
typedef std:: pair <int,int> pair;
const int N=2000005;
std:: vector <pair> p[4];
int ins[N],out[N],s[N],r[N],tot;
int n,m,k;
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):v,ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void get(int i,int x,int y) {
if (!x) p[0].push_back(pair(y,i));
else if (y==m) p[1].push_back(pair(x,i));
else if (x==n) p[2].push_back(pair(y,i));
else p[3].push_back(pair(x,i));
}
int main(void) {
n=read(),m=read(),k=read();
rep(i,1,k) {
int x1=read(),y1=read(),x2=read(),y2=read();
if ((!x1||x1==n||!y1||y1==m)&&(!x2||x2==n||!y2||y2==m)) {
get(i,x1,y1),get(i,x2,y2);
}
r[i]=1LL*rand()*rand()+1;
}
rep(i,0,3) std:: sort(p[i].begin(),p[i].end());
rep(j,0,1) {
for (int i=0;i<p[j].size();++i) {
int x=p[j][i].se; ++tot;
s[tot]=s[tot-1]^r[x];
if (!ins[x]) ins[x]=tot;
else out[x]=tot;
}
}
rep(j,2,3) {
std:: reverse(p[j].begin(),p[j].end());
for (int i=0;i<p[j].size();++i) {
int x=p[j][i].se; ++tot;
s[tot]=s[tot-1]^r[x];
if (!ins[x]) ins[x]=tot;
else out[x]=tot;
}
}
rep(i,1,k) {
if (out[i]<ins[i]) std:: swap(out[i],ins[i]);
if (s[ins[i]-1]!=s[out[i]]) {
puts("NO"); return 0;
}
}
puts("YES");
return 0;
}