1、这道题涉及线段树的区间修改。我交了17次才过(从中午写到半夜!)。
2、刚开始想把[a,b)作为区间(选取左闭右开区间),带来了一系列麻烦,最后还是把图形分成若干个矩形,比如说(1,10,2)这组数据就能分成9个矩形。将最左端的数字作为矩形的编号(选取闭区间)。
3、开始我只用了一个setv作为懒标记,结果总是TLE,主要是因为每次得到答案的时候都要接近叶子结点了。后来添加了两个信息maxv和minv,时间大大减少。
4、修改后持续WA,发现maxv和minv的初始值设错了,我分别设成了-1和100010——注意这两个变量保存的是这个“区间”里面的最值,当没有矩形的时候,最小值和最大值都应为0(因为高度为0)。
5、然后发现当我修改了一个区间的setv值的时候,并没有相应地修改其祖先的值,但是修改后仍旧WA,仔细检查后发现maintain函数并没有及时把懒标记setv转化成区间信息。于是在开头加上一句"if setv[o]>=0..."后终于AC。
6、这道题是新加坡07年的区域赛题,UVaOJ上只有70个人过,做出来还是蛮有成就感的。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int maxv[400010],minv[400010],setv[400010],cnt,v,y1,y2;
struct interval{
int l,r,h;
};
interval a[100010];
void pushdown(int o){
int lc=o*2,rc=o*2+1;
if(setv[o]>=0){
setv[lc]=setv[rc]=setv[o];
setv[o]=-1;
}
}
void maintain(int o,int L,int R){
int lc=o*2,rc=o*2+1;
if(setv[o]>=0){
maxv[o]=minv[o]=setv[o];
}
else if(R>L){
maxv[o]=max(maxv[lc],maxv[rc]);
minv[o]=min(minv[lc],minv[rc]);
}
return;
}
void update(int o,int L,int R){
int lc=o*2,rc=o*2+1;
if(setv[o]>=0){
maxv[o]=minv[o]=setv[o];
}
if(y1<=L&&y2>=R){
if(v>=maxv[o]){
cnt+=R-L+1;
maxv[o]=minv[o]=setv[o]=v;
int t=o;
while(t>1){
t/=2;
maxv[t]=max(maxv[o],maxv[t]);
minv[t]=min(minv[o],minv[t]);
}
return;
}
else if(v<minv[o]) return;
else{
pushdown(o);
int M=L+(R-L)/2;
if(y1<=M) update(lc,L,M);else maintain(lc,L,M);
if(y2>M) update(rc,M+1,R);else maintain(rc,M+1,R);
}
}else{
pushdown(o);
int M=L+(R-L)/2;
if(y1<=M) update(lc,L,M);else maintain(lc,L,M);
if(y2>M) update(rc,M+1,R);else maintain(rc,M+1,R);
}
maintain(o,L,R);
return;
}
int main()
{
//freopen("a.txt","r",stdin);
int T,n,tmax,tmin;
scanf("%d",&T);
while(T--){
cnt=0;tmax=-1;tmin=100010;
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].h);
a[i].r--;
if(a[i].l<tmin) tmin=a[i].l;
if(a[i].r>tmax) tmax=a[i].r;
}
memset(setv,-1,sizeof(setv));
memset(maxv,0,sizeof(maxv));
memset(minv,0,sizeof(minv));
for(int i=0;i<n;i++){
y1=a[i].l;y2=a[i].r;v=a[i].h;
update(1,tmin,tmax);
}
printf("%d\n",cnt);
}
scanf("%d",&n);
return 0;
}
2、刚开始想把[a,b)作为区间(选取左闭右开区间),带来了一系列麻烦,最后还是把图形分成若干个矩形,比如说(1,10,2)这组数据就能分成9个矩形。将最左端的数字作为矩形的编号(选取闭区间)。
3、开始我只用了一个setv作为懒标记,结果总是TLE,主要是因为每次得到答案的时候都要接近叶子结点了。后来添加了两个信息maxv和minv,时间大大减少。
4、修改后持续WA,发现maxv和minv的初始值设错了,我分别设成了-1和100010——注意这两个变量保存的是这个“区间”里面的最值,当没有矩形的时候,最小值和最大值都应为0(因为高度为0)。
5、然后发现当我修改了一个区间的setv值的时候,并没有相应地修改其祖先的值,但是修改后仍旧WA,仔细检查后发现maintain函数并没有及时把懒标记setv转化成区间信息。于是在开头加上一句"if setv[o]>=0..."后终于AC。
6、这道题是新加坡07年的区域赛题,UVaOJ上只有70个人过,做出来还是蛮有成就感的。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int maxv[400010],minv[400010],setv[400010],cnt,v,y1,y2;
struct interval{
int l,r,h;
};
interval a[100010];
void pushdown(int o){
int lc=o*2,rc=o*2+1;
if(setv[o]>=0){
setv[lc]=setv[rc]=setv[o];
setv[o]=-1;
}
}
void maintain(int o,int L,int R){
int lc=o*2,rc=o*2+1;
if(setv[o]>=0){
maxv[o]=minv[o]=setv[o];
}
else if(R>L){
maxv[o]=max(maxv[lc],maxv[rc]);
minv[o]=min(minv[lc],minv[rc]);
}
return;
}
void update(int o,int L,int R){
int lc=o*2,rc=o*2+1;
if(setv[o]>=0){
maxv[o]=minv[o]=setv[o];
}
if(y1<=L&&y2>=R){
if(v>=maxv[o]){
cnt+=R-L+1;
maxv[o]=minv[o]=setv[o]=v;
int t=o;
while(t>1){
t/=2;
maxv[t]=max(maxv[o],maxv[t]);
minv[t]=min(minv[o],minv[t]);
}
return;
}
else if(v<minv[o]) return;
else{
pushdown(o);
int M=L+(R-L)/2;
if(y1<=M) update(lc,L,M);else maintain(lc,L,M);
if(y2>M) update(rc,M+1,R);else maintain(rc,M+1,R);
}
}else{
pushdown(o);
int M=L+(R-L)/2;
if(y1<=M) update(lc,L,M);else maintain(lc,L,M);
if(y2>M) update(rc,M+1,R);else maintain(rc,M+1,R);
}
maintain(o,L,R);
return;
}
int main()
{
//freopen("a.txt","r",stdin);
int T,n,tmax,tmin;
scanf("%d",&T);
while(T--){
cnt=0;tmax=-1;tmin=100010;
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].h);
a[i].r--;
if(a[i].l<tmin) tmin=a[i].l;
if(a[i].r>tmax) tmax=a[i].r;
}
memset(setv,-1,sizeof(setv));
memset(maxv,0,sizeof(maxv));
memset(minv,0,sizeof(minv));
for(int i=0;i<n;i++){
y1=a[i].l;y2=a[i].r;v=a[i].h;
update(1,tmin,tmax);
}
printf("%d\n",cnt);
}
scanf("%d",&n);
return 0;
}