[扫描线][差分约束] Jzoj P4238 纪念碑
Posted comfortable
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[扫描线][差分约束] Jzoj P4238 纪念碑相关的知识,希望对你有一定的参考价值。
题解
- 题目大意:在一个n*m的区间内,有p个长方形的建筑,求在剩下的地方里求一个最大正方形的边长
- 这种题,我们可以维护x轴上的两个指针l,r每次将扫到的矩阵,拆成两条线段,运用差分约束的思想,加入线段树中
- 然后我们就可以用线段树来维护y轴,也就是维护一段最长的为0的区间tree[d].v
- 答案其实就是在r-l+1和tree[1].v中取最小值
- 当r-l+1>tree[1].v时:
- 如果r右移,r-l+1会变大,mx不会变大,所以答案不会变大
- 如果l右移,r-l+1会变小,mx可能会变大,所以答案可能会变大
- 当r-l+1<=tree[1].v时:
- 如果r右移,r-l+1会变大,mx不会变大,所以答案可能会变大
- 如果l右移,r-l+1会变小,mx可能会变大,所以答案会变小
- 那么根据上面,r右移时,就把对应标号为+1的线段加入;l右移时就把对应标号为-1的线段加入(这个东西可以用vector存)
- 现在就来考虑一下如何用线段树来维护区间的最长连续0的长度
- 那么考虑每次操作就是给一段区间+1,-1,这个可以用tag下传
- tag一定是非负数,那么就考虑两种情况:
- ①tag为正数,区间肯定就没有0,直接赋值为0
- ②tag为0时,若这是叶子,那答案为1,否则答案就必须由下面两个儿子合并上来
- 所以一个节点记录左边延伸多少,右边延伸多少,整个区间最大答案是多少就好了
代码
1 #include <cstdio> 2 #include <iostream> 3 #include <vector> 4 #define N 1000010 5 using namespace std; 6 vector<int> P[N],Q[N]; 7 struct Tree {int l,r,x,y,v;}tree[4*N]; 8 int n,m,p,l,r,ans,x1[N],x2[N],y1[N],y2[N],lazy[4*N]; 9 void build(int d,int l,int r) 10 { 11 tree[d].l=l,tree[d].r=r,tree[d].x=tree[d].y=tree[d].v=r-l+1; 12 if (l==r) return; 13 int mid=l+r>>1; 14 build(d*2,l,mid),build(d*2+1,mid+1,r); 15 } 16 void Lazy_down(int d) 17 { 18 if (lazy[d]) 19 { 20 tree[d].x=tree[d].y=tree[d].v=0; 21 return; 22 } 23 if (tree[d].l==tree[d].r) 24 { 25 tree[d].x=tree[d].y=tree[d].v=1; 26 return; 27 } 28 tree[d].x=tree[d*2].x+(tree[d*2].x==tree[d*2].r-tree[d*2].l+1)*tree[d*2+1].x; 29 tree[d].y=tree[d*2+1].y+(tree[d*2+1].y==tree[d*2+1].r-tree[d*2+1].l+1)*tree[d*2].y; 30 tree[d].v=max(tree[d*2+1].x+tree[d*2].y,max(tree[d*2].v,tree[d*2+1].v)); 31 } 32 void change(int d,int l,int r,int L,int R,int k) 33 { 34 if (L<=l&&r<=R) { lazy[d]+=k,Lazy_down(d); return; } 35 int mid=tree[d].l+tree[d].r>>1; 36 if (L<=mid) change(d*2,l,mid,L,R,k); if (mid<R) change(d*2+1,mid+1,r,L,R,k); 37 Lazy_down(d); 38 } 39 int main() 40 { 41 scanf("%d%d%d",&n,&m,&p); 42 for (int i=1;i<=p;i++) scanf("%d%d%d%d",&x1[i],&y1[i],&x2[i],&y2[i]),P[x1[i]].push_back(i),Q[x2[i]].push_back(i); 43 build(1,1,m),l=1,r=1; 44 while (r<=n) 45 { 46 for (int i=0;i<P[r].size();i++) change(1,1,m,y1[P[r][i]],y2[P[r][i]],1); 47 ans=max(ans,min(tree[1].v,r-l+1)); 48 while (tree[1].v<r-l+1) 49 { 50 for (int i=0;i<Q[l].size();i++) change(1,1,m,y1[Q[l][i]],y2[Q[l][i]],-1); 51 l++; 52 } 53 r++; 54 } 55 printf("%d",ans); 56 }
以上是关于[扫描线][差分约束] Jzoj P4238 纪念碑的主要内容,如果未能解决你的问题,请参考以下文章