UVa OJ 1232

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值