正题
题目大意
对一个全白矩阵每次选择一个矩阵颜色取反。
然后求最后所有黑色联通块的周长之和。
解题思路
因为是算周长,所以我们将一个矩阵拆分成4条边,然后将横竖分开处理。
若处理横的边,我们按照xxx为关键字排序。
然后对于xxx不同的边分开处理,那么一行最多NNN个点,我们先将这些点离散化。
我们发现一条被覆盖了奇数次的边才会被统计入答案,所以我们可以用一个差分数组维护计算一条边经过了多少次,然后统计答案。
因为总共只有8∗N8*N8∗N个点所以可以过。
时间复杂度O(NlogN)O(N\ log\ N)O(N log N)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=50100;
struct line{int x,l,r;
}a[2*N],e[2*N];
int num,n,b[2*N],s[2*N],cnt,v[2*N],ans;
void addl(int x,int l,int r)
{a[num]=(line){x,l,r};}
void adde(int x,int l,int r)
{e[num]=(line){x,l,r};}
bool cmp(line x,line y)
{return x.x<y.x;}
void work(line *a)
{int L=1,R=0;for(R=1;R<=num;){while(a[R].x==a[R+1].x) R++;cnt=0;for(int i=L;i<=R;i++)b[++cnt]=a[i].l,b[++cnt]=a[i].r;sort(b+1,b+1+cnt);cnt=unique(b+1,b+1+cnt)-b-1;for(int i=1;i<=cnt;i++)v[b[i]]=i,s[i]=0;for(int i=L;i<=R;i++)s[v[a[i].l]]++,s[v[a[i].r]]--;for(int i=1;i<=cnt;i++)s[i]+=s[i-1];for(int i=1;i<cnt;i++)ans+=(s[i]&1)*(b[i+1]-b[i]);R++;L=R;}
}
int main()
{scanf("%d",&n);for(int i=1;i<=n;i++){int x1,y1,x2,y2;scanf("%d%d%d%d",&x1,&y1,&x2,&y2);x2++,y2++;num++;addl(x1,y1,y2);adde(y2,x1,x2);num++;adde(y1,x1,x2);addl(x2,y1,y2);}sort(a+1,a+1+num,cmp);sort(e+1,e+1+num,cmp);work(a);work(e);printf("%d",ans);
}