AtCoder Regular Contest 076E Connected? 棧

Description


N*M的矩陣裏面有k對不同顏色的點,同顏色的點之間互相連邊,問所有的邊是否能不相交
k105k\le10^5

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章