SSLOJ 1351.矩形反色【差分】

本文探讨了一道算法题目,通过使用差分和离散化技术,解决了一个涉及矩形区域翻转颜色并计算边界长度的问题。核心思路在于识别边界贡献的条件,并通过数据结构优化存储与查询。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


题目:

传送门


题意:

n n n此操作,每次操作给出矩形的左上端点坐标和右下端点坐标
每次操作后对于矩形内的方块的颜色都进行取反
求边界的总长


分析:

我们试着手玩样例,发现一条边对答案存在贡献,当且仅当该边被若干个矩形覆盖了奇数次
因此我们可以用差分来记录状态
因为坐标之间相差较大,我们考虑用离散化来做到优秀的储存


代码:

#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cmath>
#define LL long long 
#define LZX Mu
using namespace std;
inline LL read() {
    LL d=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
    return d*f;
}
struct node{
	int w,l,r;
}a[100005],b[100005];
int cnt=0,ans=0;
bool cmp(node x,node y) {return x.w<y.w;}
void add1(int x,int l,int r) {a[++cnt]=(node){x,l,r};return;}
void add2(int x,int l,int r) {b[cnt]=(node){x,l,r};return;}
int d[100005],num[100005],sum[100005];
void ask(node *c)
{
	int l=1,r=0;
	for(r=1;r<=cnt;)
	{
		while(c[r].w==c[r+1].w) r++;
		int len=0;
		for(int i=l;i<=r;i++) d[++len]=c[i].l,d[++len]=c[i].r;
		sort(d+1,d+1+len);
		len=unique(d+1,d+1+len)-d-1;
		for(int i=1;i<=len;i++) num[d[i]]=i,sum[i]=0;
		for(int i=l;i<=r;i++) sum[num[c[i].l]]++,sum[num[c[i].r]]--;
		for(int i=1;i<=len;i++) sum[i]+=sum[i-1];
		for(int i=1;i<len;i++) ans+=(sum[i]&1)*(d[i+1]-d[i]);
		r++;l=r;
	}
	return;
}
int main()
{
	LL q=read();
	for(int i=1;i<=q;i++)
	{
		int x1=read(),y1=read(),x2=read()+1,y2=read()+1;
		add1(x1,y1,y2);add2(y1,x1,x2);
		add1(x2,y1,y2);add2(y2,x1,x2);
	}
	sort(a+1,a+1+cnt,cmp);sort(b+1,b+1+cnt,cmp);
	ask(a);ask(b);
	cout<<ans;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值