Description
N*M的矩陣裏面有k對不同顏色的點,同顏色的點之間互相連邊,問所有的邊是否能不相交
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;
}