标签:
题目给出n(<=100000)个长方体,给的是左下角和右上角的坐标x,y(1<=x,y<=1000000000),z(1<=z<=3),求刚好覆盖k次的体积,答案保证在long long 之内
题解
1.根据数据范围首先要想到要离散化。
2.求覆盖的面积或者体积会想到线段树维护扫描线,求体积难道要用二维线段树?这一道题是可以不的,因为1<=z<=3所以可以把体积拆开当做面积来算,当1<=z<=2就是求前面覆盖K次的面积,当2<=z<=3的时候就是求后面覆盖K次的面积,就是求两次面积。
3.求K次覆盖面积怎么办呢?把扫描线以y的大小从小往大排序,那么每一条扫描从下往上扫的时候,就有会有与上一条扫描线的纵坐标y的差值从而得到高度Δh,怎么得到与上一条扫描线之间覆盖K次的线段的长度呢?在线段树中用tree[k].sum[x]表示这个区间覆盖x次的线段长度,那么与上一条扫描线之间的覆盖k次面积就是Δh*tree[1].sum[K]。
代码
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1000010;
struct Tree{
int l,r,cover,sum[20];
}tree[N<<3];
#define clr(a,b) memset(a,b,sizeof(a))
int hase[N],cnt,LUcnt,LPcnt,n,K,pre;
struct Line{
int lx,rx,y,flag;
bool operator < (const Line& rhs)const{return y < rhs.y;}
void push(int lx,int rx,int y,int flag){
this->lx = lx,this->rx = rx,this->y = y,this->flag = flag;
}
}lineu[N<<2],linep[N<<2];
void build(int k,int l,int r){
tree[k].sum[0] = hase[r]-hase[l];
for(int i = 1;i <= 15;++i)tree[k].sum[i] = 0;
tree[k].l = l,tree[k].r = r,tree[k].cover = 0;
if(l+1 == r)return;
int mid = (l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid,r);
}
void processup(int k){
int l = tree[k].l,r = tree[k].r;
if(l+1 == r){
clr(tree[k].sum,0);
tree[k].sum[min(K+1,tree[k].cover)] = hase[r]-hase[l];
}
else{
clr(tree[k].sum,0);
for(int i = 0;i <= K+1;++i)
tree[k].sum[min(K+1,i+tree[k].cover)] = tree[k<<1].sum[i]+tree[k<<1|1].sum[i];
}
}
void update(int k,int l,int r,int flag){
if(l == r)return;
if(tree[k].l >= l && tree[k].r <= r){
tree[k].cover += flag;
}
else{
int mid = (tree[k].l+tree[k].r)>>1;
if(r <= mid)update(k<<1,l,r,flag);
if(l > mid)update(k<<1|1,l,r,flag);
}
processup(k);
}
int main(){
scanf("%d%d",&n,&K);
for(int i = 1;i <= n;++i){
int x1,x2,y1,y2,z1,z2;
scanf("%d%d%d%d%d%d",&x1,&y1,&z1,&x2,&y2,&z2);
hase[++cnt] = x1,hase[++cnt] = x2;
if(z1 == 1 && z2 == 2){
lineu[++LUcnt].push(x1,x2,y1,1);
lineu[++LUcnt].push(x1,x2,y2,-1);
}
if(z1 == 1 && z2 == 3){
lineu[++LUcnt].push(x1,x2,y1,1);
lineu[++LUcnt].push(x1,x2,y2,-1);
linep[++LPcnt].push(x1,x2,y1,1);
linep[++LPcnt].push(x1,x2,y2,-1);
}
if(z1 == 2 && z2 == 3){
linep[++LPcnt].push(x1,x2,y1,1);
linep[++LPcnt].push(x1,x2,y2,-1);
}
}
sort(hase+1,hase+1+cnt);
cnt = unique(hase+1,hase+1+cnt)-hase-1;
sort(linep+1,linep+1+LPcnt),sort(lineu+1,lineu+1+LUcnt);
for(int i = 1;i <= LUcnt;++i){
lineu[i].lx = lower_bound(hase+1,hase+cnt+1,lineu[i].lx)-hase;
lineu[i].rx = lower_bound(hase+1,hase+cnt+1,lineu[i].rx)-hase;
}
for(int i = 1;i <= LPcnt;++i){
linep[i].lx = lower_bound(hase+1,hase+cnt+1,linep[i].lx)-hase;
linep[i].rx = lower_bound(hase+1,hase+cnt+1,linep[i].rx)-hase;
}
long long res = 0;
build(1,0,cnt);
pre = lineu[1].y;
for(int i = 1;i <= LUcnt;++i){
res += 1LL*(lineu[i].y-pre)*tree[1].sum[K];
update(1,lineu[i].lx,lineu[i].rx,lineu[i].flag),pre = lineu[i].y;
}
build(1,0,cnt);
pre = linep[1].y;
for(int i = 1;i <= LPcnt;++i){
res += 1LL*(linep[i].y-pre)*tree[1].sum[K];
update(1,linep[i].lx,linep[i].rx,linep[i].flag),pre = linep[i].y;
}
cout<<res<<endl;/**/
return 0;
}
CDOJ 1335 郭大侠与“有何贵干?” (线段树&扫描线) - xgtao -
标签:
原文地址:http://www.cnblogs.com/xgtao984/p/5727911.html