算法随笔——扫描线

https://www.acwing.com/solution/content/135911/

oi-wiki扫描线

放个模板先

P5490 【模板】扫描线

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
#define re register
#define int ll
#define PII pair<int,int>
int read()
{
	int f=1,k=0;char c = getchar();
	while(c <'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9')k=(k<<1)+(k<<3)+(c^48),c=getchar();
	return k*f;
}

const int N = 2e6+5; //数组尽量开大点 16倍

int n;
vector<int> v;
struct node
{
	int x,y1,y2,k; //存储一条竖着的边
}a[N];
struct tree
{
	int len = 0,cnt = 0;
}t[N];
bool cmp(node a,node b)
{
	return a.x < b.x;
}
int tot;
int find(int x)
{
	return lower_bound(v.begin(),v.end(),x) - v.begin() + 1;
}
void pushup(int k ,int l,int r)
{
	if (t[k].cnt) t[k].len = v[r+1 - 1] - v[l - 1]; // cnt > 0表示该区间已完全覆盖,len改为区间长度
	else  t[k].len = t[k<<1].len + t[k<<1|1].len; //没有完全覆盖则从子节点获取len
}
void modify(int k,int l,int r,int x,int y,int v)
{
	if (x > r || y < l) return;
	if (x <= l && r <= y)
	{
		t[k].cnt += v;
		pushup(k,l,r); //当cnt变化时,len也会变, 因此这里也需要pushup
		return;
	}
	int mid = (l +r) >> 1;
	modify(k<<1,l,mid,x,y,v);
	modify(k<<1|1,mid + 1,r,x,y,v);
	pushup(k,l,r); // 正常pushup
}


signed main()
{
	cin >> n;

	for (int i  = 1;i <= n;i++)
	{
		int x1 = read(),y1 = read(),x2 = read(),y2 = read();
		a[++tot] = {x1,y1,y2,1}; //入边 -> 1
		a[++tot] = {x2,y1,y2,-1};//出边 -> -1
		v.push_back(y1);v.push_back(y2);
	}
	sort(v.begin(),v.end());
	sort(a + 1,a + tot + 1,cmp);
	v.erase(unique(v.begin(),v.end()),v.end()); //离散化
	int ans = 0;
	for (int i = 1;i <= tot;i++)
	{
		ans += (a[i].x-a[i-1].x) * t[1].len; //长 x 宽
		modify(1,1,v.size(),find(a[i].y1),find(a[i].y2)-1,a[i].k);//r-1是因为对应的区间下标少1
	}
	cout << ans << endl;
	return 0;
}
posted @   codwarm  阅读(37)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示