http://uoj.ac/problem/25
其实这个题在ACM/ICPC Shanghai Training Camp的比赛中也有见过,当时赛题中还要求叠加一个区间加标记,在我的对拍查错的配合下,我们队的sol神犇当时A掉了那个题。
这个题很显然比上海的赛题简单很多对吧,不过我还是太弱了,加之第一次做交互题,所以花了一上午才AC。。。。
注意到应用在序列上的操作可以总结为”如果它的初值( val ) 小于max_tag,那么最终它等于max_tag,如果它的初值大于min_tag,那么最终它等于min_tag,否则它最终等于初值 ”的形式
我们不妨设区间中元素 i 的值为 val[i],要对其取max{max_tag[i],min{min_tag[i],val[i]}} (注意下取max和min的顺序,不过好像先取后取都无所谓),我们的线段树需要支持以下操作:
1. SegmentMax(L,R,h):对区间[L,R]取max{h}
2. SegmentMin(L,R,h):对区间[L,R]取min{h}
可以转换成
1. updateMax(o,h):对线段树结点o对应的区间取max{h}
2. updateMin(o,h):对线段树结点o对应的区间取min{h}
对于(1)而言,若 h<max_tag[o],max_tag[o]=h,若h<min_tag[o],min_tag[o]=h ,这个的正确性自己脑补下就行了。
对于(2)也是如此。
于是此题就做出来了
#include "wall.h"
const int MAXN=8000010;
const int MAXH=100000;
int max_tag[MAXN],min_tag[MAXN],val[MAXN];
void updateMax(int o,int h) //修改结点o的max标记为h
{
if(h>max_tag[o]) max_tag[o]=h;
if(h>min_tag[o]) min_tag[o]=h;
}
void updateMin(int o,int h) //修改结点o的min标记为h
{
if(h<max_tag[o]) max_tag[o]=h;
if(h<min_tag[o]) min_tag[o]=h;
}
void pushdown(int o) //下传标记操作
{
updateMax(o<<1,max_tag[o]);
updateMax(o<<1|1,max_tag[o]);
max_tag[o]=0;
updateMin(o<<1,min_tag[o]);
updateMin(o<<1|1,min_tag[o]);
min_tag[o]=MAXH;
}
void build(int o,int L,int R)
{
if(L==R)
{
max_tag[o]=min_tag[o]=val[o]=0;
return;
}
int M=(L+R)>>1;
max_tag[o]=0;
min_tag[o]=MAXH;
val[o]=0;
build(o<<1,L,M);
build(o<<1|1,M+1,R);
}
void changeMax(int o,int L,int R,int ql,int qr,int h) //[ql,qr]区间取max
{
if(ql<=L&&R<=qr)
{
updateMax(o,h);
return;
}
pushdown(o);
int M=(L+R)>>1;
if(ql<=M)
changeMax(o<<1,L,M,ql,qr,h);
if(M<qr)
changeMax(o<<1|1,M+1,R,ql,qr,h);
}
void changeMin(int o,int L,int R,int ql,int qr,int h) //[ql,qr]区间取min
{
if(ql<=L&&R<=qr)
{
updateMin(o,h);
return;
}
pushdown(o);
int M=(L+R)>>1;
if(ql<=M)
changeMin(o<<1,L,M,ql,qr,h);
if(M<qr)
changeMin(o<<1|1,M+1,R,ql,qr,h);
}
void writeans(int o,int L,int R,int *&output)
{
if(L==R)
*output++=max_tag[o];
else
{
pushdown(o);
int M=(L+R)>>1;
writeans(o<<1,L,M,output);
writeans(o<<1|1,M+1,R,output);
}
}
void buildWall(int n,int k,int op[],int left[],int right[],int height[],int finalHeight[])
{
build(1,1,n);
for(int i=0;i<k;i++)
{
if(op[i]==1) //区间取max
changeMax(1,1,n,left[i]+1,right[i]+1,height[i]);
else //区间取min
changeMin(1,1,n,left[i]+1,right[i]+1,height[i]);
}
int *output=finalHeight;
writeans(1,1,n,output);
}