题意:求矩形并周长
这里给出一组hack数据
47
-1155 -1105 -285 -930
-1115 -765 -375 -615
-480 -705 -285 -165
-1200 -705 -1025 -175
-1105 -275 -385 -105
-1165 -10 -285 185
-1160 315 -710 400
-1195 340 -1070 655
-1140 580 -265 655
-480 325 -335 395
-390 365 -265 620
-770 365 -665 610
-1195 815 -1070 1110
-760 825 -660 1100
-405 810 -275 1115
-700 780 -360 860
-695 1065 -360 1130
-1110 775 -735 860
-1110 1070 -730 1145
-95 -1065 260 140
80 -725 460 750
-135 135 840 490
-135 135 750 490
40 -520 945 -210
620 -595 695 215
-5 670 610 855
-75 550 -25 830
240 815 370 1085
-90 980 145 1125
150 280 315 490
-155 -1035 -90 -845
815 855 1030 950
980 785 1165 860
985 945 1160 1015
835 730 895 1075
695 875 790 935
420 -1165 650 -520
815 -1090 945 -210
800 -130 1160 65
980 120 1150 690
995 -1140 1180 -125
1050 -825 1135 -195
865 -90 1090 10
1045 280 1090 625
1065 -655 1115 -245
70 -1155 315 -790
110 -1005 225 -825
这道题呢,有两种方法可以做。一种是两根扫描线,一种是对于每个查询的X轴上的长度,可以通过作与上一个状态的差值的绝对值来得到的,那么要乘以多少次Y轴的长度,就只会受到连续区间段的影响。
我一开始想的是用两根扫描线去做。但是一直会wa,不知道为什么。自己实在想不出来,去问了学长和龙佬,最后发现bug。
我们扫描线时,需要将边从升序排序。如果两个边高度相同呢?这时候边的顺序就有可能会导致bug。
如图,我们有4条边,按照之前想的办法,我们进行处理,我们先放进去1这号边,再放入2这号边,实际上,这时候我们已经把下面的那个矩形块的周长完全计算了一遍,这时候其实我们已经算了2号的这条边,但是呢,我们再放进去3这号边的时候,其实又要去把3这号边的值给计算一遍,而且完完全全的是加3这号的边,那么实际上就把2这条边连续加了两次,而实际上呢,它并未产生贡献。
虽然,不经过这样的考虑也是可以AC的,弱数据(可能是随机数造的吧开森),但是今天突然被问到这个,于是想到了,扫描线确实还有一些小细节尤为重要,现在写下来,自省。
处理的方式呢?我们不妨在同等的高度上,我们先放进去要增入的边,在减去其余的边,我们就可以让那些由于先减后删多出来的贡献给消除掉了。所以,在对于y的排序上,我们先考虑y是否相同,若是相同了,我们先放入“val == 1”的加的部分,然后再是“val == -1”的减的部分。
(转自https://blog.csdn.net/qq_41730082/article/details/104036421)
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
//#pragma GCC optimize(3,"Ofast","inline")
using namespace std;
#define LL long long
#define MT(a,b) memset(a,b,sizeof(a))
const int maxn=5E3+5;
const int ONF=-0x3f3f3f3f;
const int INF=0x3f3f3f3f;
struct node{
LL sum;
int cnt;
}tree[maxn<<3];
struct node0{
int x1,y1,x2,y2;
}s[maxn<<2];
struct node1{
int x1,x2,y;
int kind;
}edge[maxn<<2];
bool cmp(node1 a,node1 b){ return a.y==b.y?a.kind>b.kind:a.y<b.y;}
int lsh[maxn<<2];//k=1h k=0s
void push_up(int l,int r,int root){
if (tree[root].cnt) tree[root].sum=lsh[r+1]-lsh[l];
else if (l==r) tree[root].sum=0;
else tree[root].sum=tree[root<<1].sum+tree[root<<1|1].sum;
}
void update(int l,int r,int ql,int qr,int root,int cnt){
if (l==ql&&r==qr){
tree[root].cnt+=cnt;
push_up(l,r,root);
return;
}
int mid=(l+r)>>1;
if (qr<=mid) update(l,mid,ql,qr,root<<1,cnt);
else if (ql>mid) update(mid+1,r,ql,qr,root<<1|1,cnt);
else{
update(l,mid,ql,mid,root<<1,cnt);
update(mid+1,r,mid+1,qr,root<<1|1,cnt);
}
push_up(l,r,root);
}
int main (){
int n;
while (~scanf("%d",&n)){
int cnt=0;
for (int i=1;i<=n;i++){
int x1,x2,y1,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
s[i].x1=x1,s[i].y1=y1,s[i].x2=x2,s[i].y2=y2;
edge[++cnt].x1=x1,edge[cnt].x2=x2,edge[cnt].y=y1,edge[cnt].kind=1,lsh[cnt]=x1;
edge[++cnt].x1=x1,edge[cnt].x2=x2,edge[cnt].y=y2,edge[cnt].kind=-1,lsh[cnt]=x2;
}
sort(edge+1,edge+1+cnt,cmp);
sort(lsh+1,lsh+1+cnt);
int len=unique(lsh+1,lsh+1+cnt)-lsh;
LL ans=0;
LL last=0;
for (int i=1;i<=cnt;i++){
int l=lower_bound(lsh+1,lsh+len,edge[i].x1)-lsh;
int r=lower_bound(lsh+1,lsh+len,edge[i].x2)-lsh-1;
update(1,len,l,r,1,edge[i].kind);
ans+=abs(tree[1].sum-last);
last=tree[1].sum;
}
cnt=0;
for (int i=1;i<=n;i++){
int x1=s[i].y1,x2=s[i].y2,y1=s[i].x1,y2=s[i].x2;
edge[++cnt].x1=x1,edge[cnt].x2=x2,edge[cnt].y=y1,edge[cnt].kind=1,lsh[cnt]=x1;
edge[++cnt].x1=x1,edge[cnt].x2=x2,edge[cnt].y=y2,edge[cnt].kind=-1,lsh[cnt]=x2;
}
sort(edge+1,edge+1+cnt,cmp);
sort(lsh+1,lsh+1+cnt);
len=unique(lsh+1,lsh+1+cnt)-lsh;
last=0;
for (int i=1;i<=cnt;i++){
int l=lower_bound(lsh+1,lsh+len,edge[i].x1)-lsh;
int r=lower_bound(lsh+1,lsh+len,edge[i].x2)-lsh-1;
update(1,len,l,r,1,edge[i].kind);
ans+=abs(tree[1].sum-last);
last=tree[1].sum;
}
printf("%lld\n",ans);
}
return 0;
}