终于调出来了,恶心死我了- -
http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=19080
刚恶补扫描线,做了几道入门题,然后继续找题,网上推荐了这道题,就打算来做一下。
恩,题意还是比较简单,求矩形的面积*权值,重叠部分*最大权值。
卧槽,好像挺简单,恩,不对呀,怎么找到最大,于是考虑暴力枚举- -挂了~~~~
抽象一下,把权值pi当成第3维,如果重叠部分最大权值构成的长方体一定在其他权值构成之上.
简而言之,就是求长方体体积并。
思路也不复杂,假设第三维最大为h,把整张图分成h份,每一个单位高度求一个面积并,加起来就好了。
听起来很简单- - 不过确实写起来有点坑爹(找了一份AC代码对拍,然后慢慢调)。
注意以下细节:
①只有三种高度,拆边的时候把每条边高度(权值)记录下来,然后把h排个序,3重循环枚举高度,总的体积为sum,
当前层面积为ans,sum+=ans*(h[i]-h[i-1]),想象一下,就是把体积分成三段,每一段的高度就是h[i]-h[i-1].
当时我没有记录高度,而是记录的种子编号,然后就把高度排了序,结果,你懂的~~~ (一片混乱~)
②每次是对边L中Li.h>=cur.h的,所以需要把当前要操作的边用一个新的东西保存。 然后依次从左往右扫,加入答案。 之前没有进行这一步操作,结果计算ans+=T[1].len[1]*(L[i+1].x-L[i].x)的时候,有可能L[i+1]这条边是不在当前层的,就bug了。
注意一下细节,然后就轻松打出二维时候的扫描线矩形面积并,就ok了!
AC代码:(人懒,替换了所有的Int为LL,空间有点大)
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<cmath>
#include<vector>
#define LL long long
using namespace std;
const LL maxn=100000+20;
const LL k=1;
/*
体积并
*/
LL n,m;
LL h[5];
struct line
{
LL x,y1,y2,flag,h;
line(LL x,LL y1,LL y2,LL flag,LL h)
{
this->x=x;
this->y1=y1;
this->y2=y2;
this->flag=flag;
this->h=h;
}
bool operator<(const line&p)const
{
return x<p.x;
}
};
vector<line>L;
vector<line>N;
LL det[2*maxn];
LL tot;
LL find(LL x)
{
return lower_bound(det+1,det+tot+1,x)-det;
}
struct node
{
LL l,r,flag;
LL len[5];
void set(LL l,LL r,LL flag)
{
this->l=l;
this->r=r;
this->flag=flag;
}
}T[8*maxn];
void pushup(LL i)
{
LL l=T[i].l;
LL r=T[i].r;
for(LL j=0;j<=k;j++)T[i].len[j]=0;
if(l==r)
{
LL t=min(T[i].flag,k);
T[i].len[t]=det[l+1]-det[l];
}
else
{
for(LL j=0;j<=k;j++)
{
LL t=min(T[i].flag+j,k);
T[i].len[t]+=T[i<<1].len[j]+T[i<<1|1].len[j];
}
}
}
void build(LL i,LL l,LL r)
{
T[i].set(l,r,0);
if(l==r)
{
pushup(i);
return ;
}
LL mid=(l+r)>>1;
build(i<<1,l,mid);
build(i<<1|1,mid+1,r);
pushup(i);
}
void updata(LL i,LL L,LL R,LL x)
{
LL l=T[i].l;
LL r=T[i].r;
if(l>=L&&r<=R)
{
T[i].flag+=x;
pushup(i);
return ;
}
LL mid=(l+r)>>1;
if(L<=mid)updata(i<<1,L,R,x);
if(R>mid)updata(i<<1|1,L,R,x);
pushup(i);
}
int main()
{
//freopen("1.in","r",stdin);
//freopen("1.out","w",stdout);
LL cas;
scanf("%I64d",&cas);
LL x1,y1,x2,y2,p;
for(LL yu=1;yu<=cas;yu++)
{
tot=0;
L.clear();
scanf("%I64d%I64d",&n,&m);
for(LL i=1;i<=m;i++)scanf("%I64d",&h[i]);
for(LL i=1;i<=n;i++)
{
scanf("%I64d%I64d%I64d%I64d%I64d",&x1,&y1,&x2,&y2,&p);
L.push_back(line(x1,y1,y2,1,h[p]));
L.push_back(line(x2,y1,y2,-1,h[p]));
det[++tot]=y1;
det[++tot]=y2;
}
sort(L.begin(),L.end());
sort(det+1,det+tot+1);
sort(h+1,h+m+1);
LL t=tot;
tot=unique(det+1,det+t+1)-det-1;
LL sum=0;
for(LL gh=1;gh<=m;gh++)
{
build(1,1,tot);
LL ans=0;
N.clear();
for(LL i=0;i<L.size();i++)
{
if(L[i].h>=h[gh])
{
N.push_back(L[i]);
}
}
for(LL i=0;i<N.size()-1;i++)
{
LL l=find(N[i].y1);
LL r=find(N[i].y2);
updata(1,l,r-1,N[i].flag);
LL yt=N[i+1].x-N[i].x;
ans+=T[1].len[k]*yt;
}
sum+=ans*(h[gh]-h[gh-1]);
}
printf("Case %I64d: %I64d\n",yu,sum);
}
return 0;
}