OK,现在来填这个坑。题目虽然说是一个需要维护的三维坐标,但是由于z巨小(1->3)所以直接用二维的扫描线就好了,然后把长方体的高拆了,就变成了求两次扫描线求两次面积再相加就好了(具体可以看代码)。这里由于需要计算被覆盖k次的矩阵的面积,所以需要用线段树来维护当前扫描线被覆盖k次的区域的长度,然后每次向上找新的扫描线的时候就用 △h * 覆盖k次的区域长度
1.线段树维护的扫描线是很多段区间,共同组成一条扫描线
2.每次更新 △h 用pre存储上一次的 纵坐标y
3.横坐标需要离散化
4.把每一条新加入的线段看成一条扫描线,所以可能会有高度相同的扫描线但是最终并不影响答案
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ls u<<1,l,mid
#define rs u<<1|1,mid,r
#define maxn 100020
#define ll long long
using namespace std;
int n , k;
struct Line{
int lx,rx,y,flag;
bool operator<(const Line& b)const{return y<b.y;}
void join(int llx,int rrx,int yy,int fflag){
lx=llx,rx=rrx,y=yy,flag=fflag;//初始化
}
}linea[maxn*4],lineb[maxn*4];//a是第一层 b是第二层
int cnta,cntb;//a的线段数 b的线段数
struct node{
int l,r,sum[15],cover;//sum[i]表示覆盖i次的扫描线长度
void clear(){
memset(sum,0,sizeof(sum));cover=0;l=r=0;
}
}nod[maxn*8];
int cur[maxn*8],cnt;//用于离散化 横坐标
bool cmp(int a,int b){return a<b;}
ll ans;
void build(int u,int l,int r){
nod[u].clear();
nod[u].l=l;nod[u].r=r;
nod[u].sum[0]=cur[r]-cur[l];
if(l==r-1){
return;
}
int mid=(l+r)>>1;
build(ls);
build(rs);
}
void push_up(int u){
int l=nod[u].l,r=nod[u].r;
memset(nod[u].sum,0,sizeof(nod[u].sum));
if(l==r-1){
nod[u].sum[min(k+1,nod[u].cover)]=cur[r]-cur[l];
}else{
for(int i=0;i<=k+1;i++)
nod[u].sum[min(k+1,i+nod[u].cover)]=nod[u<<1].sum[i]+nod[u<<1|1].sum[i];
}
}
void updata(int u,int l,int r,int x,int y,int add){
if(x==y)return;
if(l>=x&&r<=y){
nod[u].cover+=add;
}
else{
int mid=(l+r)>>1;
if(y>mid)updata(rs,x,y,add);
if(x<mid)updata(ls,x,y,add);
}
push_up(u);
}
void solve(){
build(1,0,cnt);
int pre=linea[1].y;//每一条线段作为一条扫描线,计算两条扫描线之间的覆盖k次的面积
for(int i=1;i<=cnta;i++){
ans+=(ll)(linea[i].y-pre)*nod[1].sum[k];
updata(1,0,cnt,linea[i].lx,linea[i].rx,linea[i].flag);
pre=linea[i].y;
}
build(1,0,cnt);
pre=lineb[1].y;//每一条线段作为一条扫描线,计算两条扫描线之间的覆盖k次的面积
for(int i=1;i<=cntb;i++){
ans+=(ll)(lineb[i].y-pre)*nod[1].sum[k];
updata(1,0,cnt,lineb[i].lx,lineb[i].rx,lineb[i].flag);
pre=lineb[i].y;
}
}
int main(){
scanf("%d%d",&n,&k);
int x1,y1,z1,x2,y2,z2;
for(int i=1;i<=n;i++){
scanf("%d%d%d%d%d%d",&x1,&y1,&z1,&x2,&y2,&z2);
cur[++cnt]=x1;cur[++cnt]=x2;
if(z1==1&&z2==2){//加入线段(可能有错)
linea[++cnta].join(x1,x2,y1,1);
linea[++cnta].join(x1,x2,y2,-1);
}
if(z1==1&&z2==3){
linea[++cnta].join(x1,x2,y1,1);
linea[++cnta].join(x1,x2,y2,-1);
lineb[++cntb].join(x1,x2,y1,1);
lineb[++cntb].join(x1,x2,y2,-1);
}
if(z1==2&&z2==3){
lineb[++cntb].join(x1,x2,y1,1);
lineb[++cntb].join(x1,x2,y2,-1);
}
}
sort(linea+1,linea+1+cnta);
sort(lineb+1,lineb+1+cntb);
sort(cur+1,cur+cnt+1,cmp);
cnt=unique(cur+1,cur+cnt+1)-cur-1;
for(int i=1;i<=cnta;i++){//把原来的线段的坐标换上显得编号
linea[i].lx=lower_bound(cur+1,cur+1+cnt,linea[i].lx)-cur;
linea[i].rx=lower_bound(cur+1,cur+1+cnt,linea[i].rx)-cur;
}
for(int i=1;i<=cntb;i++){//把原来的线段的坐标换上显得编号
lineb[i].lx=lower_bound(cur+1,cur+1+cnt,lineb[i].lx)-cur;
lineb[i].rx=lower_bound(cur+1,cur+1+cnt,lineb[i].rx)-cur;
}
solve();//解决问题
printf("%lld",ans);
return 0;
}