jzoj1495 宝石 解题报告[扫描线]
Posted xxzh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jzoj1495 宝石 解题报告[扫描线]相关的知识,希望对你有一定的参考价值。
题目大意就是在一个正方形内给定一些点,用一个小正方形去覆盖,由于每个点的分数不同,因此肯定有所谓最大得分,算出最大得分就是我们的任务
我们放正方形,有一个点放在正方形的一角上是最优的,这里我们采用左下角
把输入的点按照x离散化,再按照y进行排序,考虑从下到上扫描线。线怎么来呢?我们把每个点置于小矩形的左下角,每个点就拥有了一个对应的范围,对于每一个范围我们把上边界所在直线进行扫描。
想象各点范围相交的地方肯定是这些点的分数都可以取到的。
在向上扫描的过程中,我们相当于是将一个长为m的矩形(离散化之后就是cnt),宽为k的矩形不断想上移动,然后去其中长为k的得分最大的一段。具体实现就是在扫描线的线段树上维护区间最大值就可以了。
下面附上代码:
#include<algorithm> #include<cstdio> using namespace std; const int maxn=5e4+15; int m,n,k,tot,cnt; int left[maxn<<4],right[maxn<<4]; struct STAR { int id,x,y,l; bool fl; }a[maxn<<4],b[maxn<<4]; struct node { int l,r,m,lazy; }t[maxn<<4]; inline int read() { char ch=getchar(); int s=0,f=1; while (!(ch>=‘0‘&&ch<=‘9‘)) {if (ch==‘-‘) f=-1;ch=getchar();} while (ch>=‘0‘&&ch<=‘9‘) {s=(s<<3)+(s<<1)+ch-‘0‘;ch=getchar();} return s*f; } bool cmp(STAR a,STAR b) {return a.x<b.x;} bool CMP(STAR a,STAR b) {if (a.y==b.y) return a.l>b.l;else return a.y<b.y;} void build(int u,int l,int r) { t[u].l=l; t[u].r=r; t[u].lazy=t[u].m=0; if (l==r) return; int mid=l+r>>1; build(u<<1,l,mid); build(u<<1|1,mid+1,r); } void down(int u) { if (t[u].lazy) { int k=t[u].lazy; t[u].lazy=0; t[u<<1].lazy+=k; t[u<<1|1].lazy+=k; t[u<<1].m+=k; t[u<<1|1].m+=k; } } void add(int u,int l,int r,int k) { if (t[u].l>=l&&t[u].r<=r) { t[u].m+=k; t[u].lazy+=k; down(u); return; } down(u); int mid=t[u].l+t[u].r>>1; if (l<=mid) add(u<<1,l,r,k); if (r>mid) add(u<<1|1,l,r,k); t[u].m=max(t[u<<1].m,t[u<<1|1].m); return; } int query(int u,int l,int r) { if (t[u].l>=l&&t[u].r<=r) return t[u].m; down(u); int ans=0,mid=t[u].l+t[u].r>>1; if (l<=mid) ans=query(u<<1,l,r); if (r>mid) ans=max(ans,query(u<<1|1,l,r)); return ans; } int main() { m=read();n=read();k=read(); for (int i=1;i<=n;i++)//a数组用来离散化 { a[i].x=read();a[i].y=read();a[i].l=read(); a[i].id=i; a[i].fl=0; b[i].y=a[i].y;//扫描线左端点 b[i].id=i; b[i].l=a[i].l; } tot=n; for (int i=1;i<=n;i++) { a[++tot].id=i; a[tot].x=a[i].x+k; a[tot].fl=1; } sort(a+1,a+1+tot,cmp);//按x排序 for (int i=1;i<=tot;i++) { int tt=0; if (a[i].x==a[i-1].x&&i!=1) tt=cnt; else tt=++cnt; if (!a[i].fl) left[a[i].id]=tt; else right[a[i].id]=tt; } tot=n; for (int i=1;i<=n;i++) { b[++tot].id=b[i].id;//扫描线右端点 b[tot].l=-b[i].l; b[tot].y=b[i].y+k; } sort(b+1,b+1+tot,CMP);//按y排序 build(1,1,cnt); int ans=0; for (int i=1;i<=tot;i++) { if (b[i].l>0) { int sum=query(1,left[b[i].id],right[b[i].id]);//只有在b[i]的范围内才能加上b[i].l if (sum+b[i].l>ans) ans=b[i].l+sum; } add(1,left[b[i].id],right[b[i].id],b[i].l); } printf("%d",ans); return 0; }
以上是关于jzoj1495 宝石 解题报告[扫描线]的主要内容,如果未能解决你的问题,请参考以下文章
[jzoj 5661] 药香沁鼻 解题报告 (DP+dfs序)
[JZOJ4024] [佛山市选2015] 石子游戏 解题报告
[jzoj 6084] [GDOI2019模拟2019.3.25] 礼物 [luogu 4916] 魔力环 解题报告(莫比乌斯反演+生成函数)