BZOJ4364 [IOI2014]wall砖墙
题目描述:
健佳正在用大小相同的砖块来砌起一面墙。这面墙由 列砖块所组成,它们从左到右的编号0至n-1。各列的高度可
以不同。各列的高度就是该列砖块的数量。健佳用如下方式来建造这面墙。最开始每列都没有砖块。此后,健佳
通过k个阶段的增加(adding)或移除(removing)砖块操作来砌墙。当所有k个阶段完成后,这面墙就砌好了。在每
个阶段中,健佳都会被告知一个连续的砖块列的范围,以及一个高度值h,然后他就完成如下过程:在增加砖块
(adding)阶段,对于给定的列范围中高度小于h的列,健佳会增加砖块使它们的高度都恰好等于h。此时他不会改
变那些高度大于或等于h的列。在移除砖块(removing)阶段,对于给定的列范围中高度大于 的列,健佳会移除砖
块使它们的高度都恰好等于h。此时他不会改变那些高度小于或等于h的列。你的任务就是计算出这面墙的最后形
状。
题解:
线段树。
考虑如何处理两个标记之间的覆盖。 首先,如果一个结点即将被打上一个down标记,值为x,并且同时它的up标记为y,那么分情况讨论。
1.如果x<y: 直接打上,无影响,因为这个区间内的值都将被修改成x~y这个范围内的值。
2.如果x>y: 此时不难看出,有了之前的up标记,这个区间内的值应该全部都大于等于y。此时再进行一个down操作,则会把这个区间内的值全部改为x。因此把up标记改为x然后打上down标记。
打up标记也是同理。
最后遍历一次就行了。
附上代码:
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; int n,k,minn[8000001],maxx[8000001]; void pushup(int k) { minn[k]=min(minn[k<<1],minn[k<<1|1]); maxx[k]=max(maxx[k<<1],maxx[k<<1|1]); } void pushdown(int k) { if(minn[k]>maxx[k<<1]) { maxx[k<<1]=minn[k]; minn[k<<1]=minn[k]; } else if(minn[k]>minn[k<<1]) minn[k<<1]=minn[k]; if(minn[k]>maxx[k<<1|1]) { maxx[k<<1|1]=minn[k]; minn[k<<1|1]=minn[k]; } else if(minn[k]>minn[k<<1|1]) minn[k<<1|1]=minn[k]; if(maxx[k]<minn[k<<1]) { maxx[k<<1]=maxx[k]; minn[k<<1]=maxx[k]; } else if(maxx[k]<maxx[k<<1]) maxx[k<<1]=maxx[k]; if(maxx[k]<minn[k<<1|1]) { maxx[k<<1|1]=maxx[k]; minn[k<<1|1]=maxx[k]; } else if(maxx[k]<maxx[k<<1|1]) maxx[k<<1|1]=maxx[k]; } void update1(int l,int r,int x,int y,int h,int k) { if(x<=l&&r<=y) { minn[k]=max(minn[k],h); maxx[k]=max(maxx[k],h); return; } int mid=(l+r)>>1; pushdown(k); if(mid>=x) update1(l,mid,x,y,h,k<<1); if(mid<y) update1(mid+1,r,x,y,h,k<<1|1); pushup(k); } void update2(int l,int r,int x,int y,int h,int k) { if(x<=l&&r<=y) { minn[k]=min(minn[k],h); maxx[k]=min(maxx[k],h); return; } int mid=(l+r)>>1; pushdown(k); if(mid>=x) update2(l,mid,x,y,h,k<<1); if(mid<y) update2(mid+1,r,x,y,h,k<<1|1); pushup(k); } void query(int l,int r,int k) { if(l==r) { printf("%d\n",minn[k]); return; } int mid=(l+r)>>1; pushdown(k); query(l,mid,k<<1); query(mid+1,r,k<<1|1); } int main() { scanf("%d%d",&n,&k); for(int i=1;i<=k;i++) { int k,x,y,z; scanf("%d%d%d%d",&k,&x,&y,&z); if(k==1) { update1(1,n,x+1,y+1,z,1); } else { update2(1,n,x+1,y+1,z,1); } } query(1,n,1); }