题解 辣鸡

传送门

因为把\(y\)打成\(x\)挂掉了,虽然就算打对也会T掉

本来以为给的都是单点,可以用哈希水过去,结果是矩形
不过矩形内部的连边可以直接算出来
那就只需要考虑矩形之间的连边
只有相邻的矩形能连边
考虑先把左边界弄成单调的
那就可以二分找与当前矩形的右侧相邻的矩形了
这里,在所有「左边界与当前矩形右边界横坐标相等」的矩形中找「与当前矩形相邻」的矩形需要再跑一次二分,否则还是会T掉
对于每个相邻矩形,令它们相邻长度为x
则有氢键数\(k = 2*(x-1)+(p[i].y_2 \neq p[l].y_2)+(p[i].y_1 \neq p[l].y_1)\)
其实质是\(2x\)减去高度相同,无法连出斜边的情况

考场上打的单二分被卡掉了,然而为什么你们n方比我nlogn跑得快啊

Code:

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long 
#define ld long double
#define usd unsigned
#define ull unsigned long long
#define int long long 

// 突然想统计一下:这是我自2021/06/10以来第 1 次因为打错变量名调一下午

#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
char buf[1<<21], *p1=buf, *p2=buf;
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n;
ll ans;
struct matrix{int x1, y1, x2, y2; inline void build() {x1=read(); y1=read(); x2=read(); y2=read(); ans+=2ll*(x2-x1)*(y2-y1);}}p[N];
inline bool cmpx(matrix a, matrix b) {return a.x1==b.x1?a.y1<b.y1:a.x1<b.x1;}
inline bool cmpy(matrix a, matrix b) {return a.y1==b.y1?a.x1<b.x1:a.y1<b.y1;}

signed main()
{
	#ifdef DEBUG
	freopen("1.in", "r", stdin);
	#endif
	
	n=read();
	for (int i=1; i<=n; ++i) p[i].build();
	int l, r, mid, q; ll x, y;
	
	sort(p+1, p+n+1, cmpx);
	for (int i=1; i<n; ++i) {
		l=i; r=n+1; q=p[i].x2;
		while (l<r) {
			mid = (l+r)>>1;
			if (p[mid].x1<=q) l=mid+1;
			else r=mid;
		}
		//cout<<l<<endl;
		++q;
		if (p[l].x1!=q) continue;
		//cout<<1<<endl;
		//while (l<=n && p[l].x1==q && p[l].y2<p[i].y1-1) ++l;
		int l2=l, r2=n+1, mid2;
		if (p[l].y2<p[i].y1-1) {
			while (l2<=r2) {
				mid2 = (l2+r2+1)>>1;
				if (p[mid2].x1==q && p[mid2].y2<p[i].y1-1) l2=mid2+1;
				else r2=mid2-1;
			}
		}
		l = l2;
		if (l>n || p[l].x1!=q) continue;
		while (l<=n && p[l].x1==q && p[l].y1<=p[i].y2+1) {
			x = min(p[i].y2, p[l].y2) - max(p[i].y1, p[l].y1) + 1;
			//cout<<x<<endl;
			if (x) ans += 2ll*(x-1)+(p[i].y2!=p[l].y2)+(p[i].y1!=p[l].y1);
			else ++ans;
			++l;
		}
	}
	
	sort(p+1, p+n+1, cmpy);
	for (int i=1; i<n; ++i) {
		l=i; r=n+1; q=p[i].y2;
		while (l<r) {
			mid = (l+r)>>1;
			if (p[mid].y1<=q) l=mid+1;
			else r=mid;
		}
		//cout<<l<<endl;
		++q;
		if (p[l].y1!=q) continue;
		//cout<<1<<endl;
		//while (l<=n && p[l].y1==q && p[l].x2<p[i].x1-1) ++l;
		#if 1
		int l2=l, r2=n+1, mid2;
		if (p[l].x2<p[i].x1-1) {
			while (l2<=r2) {
				mid2 = (l2+r2+1)>>1;
				if (p[mid2].y1==q && p[mid2].x2<p[i].x1-1) l2=mid2+1;
				else r2=mid2-1;
			}
		}
		l = l2;
		#endif
		if (l>n || p[l].y1!=q) continue;
		while (l<=n && p[l].y1==q && p[l].x1<=p[i].x2+1) {
			y = min(p[i].x2, p[l].x2) - max(p[i].x1, p[l].x1) + 1;
			//cout<<y<<endl;
			if (y) ans += 2ll*(y-1)+(p[i].x2!=p[l].x2)+(p[i].x1!=p[l].x1);
			++l;
		}
	}
	
	printf("%lld\n", ans);

	return 0;
}
上一篇:树状数组总结


下一篇:计算机图形学中点画线法(MFC)