poj 2528 线段树数据离散化+区间更新

                           POJ2528

题大意为在一片等高长度为10000000的墙上粘贴n(n<=10000)份海报,在相同区间内后粘贴的海报会覆盖之前海报,求所有操作结束后有多少张海报未被完全覆盖。
这里写图片描述
Sample Input

1
5
1 4
2 6
8 10
3 4
7 10

Sample Output

4

因为题目的数据规模较大,直接建立线段树会使用过高的空间并造成极大的空间浪费,所以需要对数据进行离散化处理。但是要注意,若直接对题目输入数据进行处理成点集则会出现异常,如
3
1 10
1 3
6 10
这组数据的结果显然为3,但直接离散化后则变为
1 4
1 2
3 4
自然得到的输出结果为错误的2,而原数据中的(3,6)这一区间内的点则被离散化后忽略了。我选择的处理方法为在离散化的同时,判断相邻数据是否相差大于1,是则将其和的一半加入到离散化数据中去。如1 10这组数据相差为9,则将(1+10)/2==5加入到数据处理中。这种情况下加入的数据并不参与实际计算,仅作为标识代表线段中点。

建树则是直接建立的求区间和的线段树。叶节点权值仅为0或1,代表当前节点是否已被覆盖。区间和则代表该区间已被覆盖的叶子节点数。若当前区间的值不为(right-left)即区间内叶子节点的数量,则代表该区间仍存在可以覆盖的点。因此,只需在处理数据时,逆向处理。因为最后粘贴的海报必然未被覆盖,而之前的数据只需要在相对应的区间内寻找是否存在未被后来者覆盖的点。存在则值自加。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int temp[300000];
int a[300000];
const int INF = -9999999;
int counts,flag;
class tree
{
    public:
    int left,right;
    int val;
    int lazy;
};
tree segtree[6000000];
void bulidetree(int node,int left,int right)
{
    segtree[node].left=left;
    segtree[node].right = right;
    segtree[node].lazy=0;
    if(left==right)
    {
        segtree[node].val = 0;
        return ;
    }
    bulidetree(node*2,left,(left+right)/2);
    bulidetree(node*2+1,(left+right)/2+1,right);
    segtree[node].val = segtree[node*2].val+segtree[node*2+1].val;
}
void pushdown(int n)
{
    if(segtree[n].lazy)
    {
        segtree[n*2].val = (segtree[n*2].right-segtree[n*2].left+1)*segtree[n].lazy;
        segtree[n*2+1].val = (segtree[n*2+1].right-segtree[n*2+1].left+1)*segtree[n].lazy;
        segtree[n*2].lazy = segtree[n].lazy;
        segtree[n*2+1].lazy=segtree[n].lazy;
        segtree[n].lazy=0;
    }
}
void update(int n,int begin,int end,int left,int right)
//查找对应区间并进行区间更新
{
    if(begin>right||end<left)
    {
        return;
    }
    pushdown(n);
    if(left<=begin&&end<=right)
    {
        if(segtree[n].val<(segtree[n].right-segtree[n].left+1))
        {

            segtree[n].val=(segtree[n].right-segtree[n].left+1);
            segtree[n].lazy = 1;
            if(flag==0)
            {
                flag++;
                counts++;
            }
        }
        return;
    }
    update(n*2,begin,(begin+end)/2,left,right);
    update(n*2+1,(begin+end)/2+1,end,left,right);
    segtree[n].val = segtree[n*2].val+segtree[n*2+1].val;
}
int main()
{
    int i,j,k,n,t,max_;
    scanf("%d",&t);
    while(t--)
    {
        counts =0;
        max_= INF;
        scanf("%d",&n);
        j = n*2;
        for(i=0;i<n;i++)
        {
            scanf("%d%d",&a[i*2],&a[i*2+1]);
            temp[i*2] = a[i*2];
            temp[i*2+1] = a[i*2+1];
            if(temp[i*2+1]-temp[i*2]>1)
                temp[j++]=temp[i*2+1]-temp[i*2];
        }
        sort(temp,temp+j);
        int size_ = unique(temp,temp+j) - temp;
        for(i=0;i<n;i++)                                   //离散化处理
        {
            a[i*2]=(lower_bound(temp,temp+size_,a[i*2])-temp)+1;
            a[i*2+1]=(lower_bound(temp,temp+size_,a[i*2+1])-temp)+1;
            if(a[i*2]>max_)
            {
                max_= a[i*2];
            }
            if(a[i*2+1]>max_)
            {
                max_= a[i*2+1];
            }
        }
        bulidetree(1,0,max_-1);
        for(i=n-1;i>=0;i--)                 //从后往前处理数据
        {
            flag =0;
            update(1,0,max_-1,a[i*2]-1,a[i*2+1]-1);
        }
        printf("%d\n",counts);
    }
   return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值