扫描线进阶
Posted Harris-H
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了扫描线进阶相关的知识,希望对你有一定的参考价值。
扫描线进阶
1.矩形面积并
P5490 【模板】扫描线
x轴平行线段按 y y y排序,离散化+点映射为线段后,从下往上线段树操作计算答案即可。
底边权为1,高边权为-1。
每次计算的面积是当前线段的长度与沿上走的高度矩形面积。
最后一条边不用算。
用一个tag标记该区间是否覆盖,如果被覆盖长度即为右端点-左端点。
否则用儿子更新长度。
code
ll X[N<<1];
struct node{
ll l,r,s,len;//l,r,s,len 结点区间表示线段[X[l],X[r+1]],s表示线段的个数,和线段长度.
}a[N<<2];
struct Line{ //储存所有矩形横边,从下往上扫描.
ll l,r,h,c; //l,r,h,c分别为横线左端点,右端点,距离x轴高度,下边权值c=1,上边权值c=-1>
bool operator<(const Line&li)const{
return h<li.h;
}
}line[N<<1];
void build(int x,int l,int r){ //建树
a[x].l=l,a[x].r=r;
if(l==r) return;
int mid=(l+r)>>1;
build(lx,l,mid);
build(rx,mid+1,r);
}
void pushup(int x){ //更新.
int l=a[x].l,r=a[x].r;
if(a[x].s) a[x].len=X[r+1]-X[l]; //如果当前线段已经被记数了,直接取长度
else a[x].len=a[lx].len+a[rx].len;//否则更新.
}
void update(int x,int L,int R,int val){ //更新线段记数情况.
int l=a[x].l,r=a[x].r;
if(X[r+1]<=L||X[l]>=R) return; //不在范围内,这里取等于 防止单点重合的情况.
if(X[l]>=L&&X[r+1]<=R){
a[x].s+=val;
pushup(x); //这里相当于直接更新长度,不用下方标记.
return;
}
update(lx,L,R,val);
update(rx,L,R,val);
pushup(x); //合并信息.
}
int main(){
int n,cnt=0;
scanf("%d",&n);
for(int i=1;i<=n;i++){
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
X[(i<<1)-1]=x1,X[(i<<1)]=x2;
line[(i<<1)-1]={x1,x2,y1,1};
line[(i<<1)]={x1,x2,y2,-1};
}
n<<=1;
sort(line+1,line+n+1);
sort(X+1,X+n+1);
cnt=unique(X+1,X+n+1)-X-1; //离散化所有端点的横坐标X.从小到大排序.
build(1,1,cnt-1);
ll ans=0;
for(int i=1;i<n;i++){ //<n 不用计算最后一条横边.
update(1,line[i].l,line[i].r,line[i].c);
ans+=a[1].len*(line[i+1].h-line[i].h);
}
printf("%lld\\n",ans);
return 0;
}
2.矩形周长并
分成两部分计算,横边长度和+竖边长度和。
横边长就是 a [ 1 ] . l e n a[1].len a[1].len
横边长度就等于abs(上一次的横边长-这一次的横边长)
竖边长度和需要维护一个竖边的条数,每次贡献就是 2 × c n t × l e n 2\\times cnt \\times len 2×cnt×len
每个结点维护一个左、右端点tag(bool),和当前区间对应的 c n t cnt cnt。
如果 l e n len len的 t a g tag tag标记为0,直接更新 l e n len len,然后左、右端点标记都赋值为真,然后 c n t = 1 cnt=1 cnt=1。
否则,用儿子来更新 l e n , c n t len,cnt len,cnt
若当前区间的左儿子的左端点和右儿子的右端点均存在。
则 c n t − 1 cnt-1 cnt−1,因为内部的两条线段会被减掉,不会计算贡献。因为这两个矩形被合并。
ll X[N<<1];
struct node{
ll l,r,s,len,c;//l,r,s,len 结点区间表示线段[X[l],X[r+1]],s表示线段的个数,和线段长度.
bool lc,rc;
}a[N<<2];
struct Line{ //储存所有矩形横边,从下往上扫描.
ll l,r,h,c; //l,r,h,c分别为横线左端点,右端点,距离x轴高度,下边权值c=1,上边权值c=-1>
bool operator<(const Line&li)const{
if(h==li.h) return c>li.c;
return h<li.h;
}
}line[N<<1];
void build(int x,int l,int r){ //建树
a[x].l=l,a[x].r=r,a[x].lc=a[x].rc=a[x].len=a[x].c=0;
if(l==r) return;
int mid=(l+r)>>1;
build(lx,l,mid);
build(rx,mid+1,r);
}
void pushup(int x){ //更新.
int l=a[x].l,r=a[x].r;
if(a[x].s) {
a[x].len=X[r+1]-X[l];
a[x].lc=a[x].rc=a[x].c=1;
}
else {
a[x].len=a[lx].len+a[rx].len;
a[x].lc=a[lx].lc,a[x].rc=a[rx].rc;
a[x].c=a[lx].c+a[rx].c;
if(a[lx].rc&&a[rx].lc) a[x].c--;
}
}
void update(int x,int L,int R,int val){ //更新线段记数情况.
int l=a[x].l,r=a[x].r;
if(X[r+1]<=L||X[l]>=R) return;
if(X[l]>=L&&X[r+1]<=R){
a[x].s+=val;
pushup(x);
return;
}
update(lx,L,R,val);
update(rx,L,R,val);
pushup(x);
}
int main(){
int n,cnt=0;
scanf("%d",&n);
for(int i=1;i<=n;i++){
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
X[(i<<1)-1]=x1,X[(i<<1)]=x2;
line[(i<<1)-1]={x1,x2,y1,1};
line[(i<<1)]={x1,x2,y2,-1};
}
n<<=1;
sort(line+1,line+n+1);
sort(X+1,X+n+1);
cnt=unique(X+1,X+n+1)-X-1; //离散化所有端点的横坐标X.从小到大排序.
build(1,1,cnt-1);
ll ans=0,pre=0;
for(int i=1;i<n;i++){
update(1,line[i].l,line[i].r,line[i].c);
ll x=a[1].len-pre;
if(x<0) x=-x;
ans+=x;
pre=a[1].len;
ans+=2*a[1].c*(line[i+1].h-line[i].h);
}
ans+=line[n].r-line[n].l;
printf("%lld\\n",ans);
return 0;
}
3.自适应辛普森积分
- 解决定积分。
- 解决到某一值就收敛的不定积分。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ygDsInKY-1627029163662)(C:\\Users\\HeHao\\AppData\\Roaming\\Typora\\typora-user-images\\image-20210716184659237.png)]
即: ∫ l r f ( x ) d x = ( r − l ) ( f ( l ) + f ( r ) + 4 f ( m ) ) 6 , m = l + r 2 \\large \\int_l^r f(x)dx=\\dfrac{(r-l)(f(l)+f(r)+4f(m))}{6},m=\\dfrac{l+r}{2} ∫lrf(x)dx=6(r−l)(f(l)+f(r)+4f(m)),m=2l+r
模板代码
il db f(db x){
// set function
}
il db simpson(db l,db r){
db m=(l+r)/2;
return (f(l)+f(r)+4*f(m))*(r-l)/6;
}
il db asr(db l,db r,db eps,db ans){
db m=(l+r)/2;
db ls=simpson(l,m),rs=simpson(m,r);
if(fabs(ls+rs-ans)<=eps*15) return ls+rs+(ls+rs-ans)/15;
return asr(l,m,eps/2,ls)+asr(m,r,eps/2,rs);
}
P4525 【模板】自适应辛普森法1
纯板子 s i m p s o n simpson simpson定积分。
#define il inline
#define db double
db a,b,c,d,l,r;
il db f(db x){
return (c*x+d)/(a*x+b《算法竞赛进阶指南》0x43线段树 扫描线算法 POJ2482
我的C语言学习进阶之旅解决 Visual Studio 2019 报错:错误 C4996 ‘fscanf‘: This function or variable may be unsafe.(代码片段
我的C语言学习进阶之旅解决 Visual Studio 2019 报错:错误 C4996 ‘fscanf‘: This function or variable may be unsafe.(代码片段
我的Android进阶之旅关于Android平台获取文件的mime类型:为啥不传小写后缀名就获取不到mimeType?为啥android 4.4系统获取不到webp格式的mimeType呢?(代码片段
Android zxing Journeyapps 条码扫描器内部片段
我的Android进阶之旅关于Android平台获取文件的mime类型:为啥不传小写后缀名就获取不到mimeType?为啥android 4.4系统获取不到webp格式的mimeType呢?(代码片段