poj2528(离散化+线段树)

本文详细阐述了如何通过离散化和线段树优化解决在特定长度范围内贴海报的问题,旨在提高算法效率并避免超时、超内存错误。离散化技术将大量数据映射到有限空间内,简化处理过程。通过实例分析,展示了离散化与线段树结合在实际应用中的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:在1-10^7的长度上贴海报,求能看到的海报数目

解题思路:10^7无论用朴素法或线段树解都会超时超内存,所以要进行离散化。所谓离散化就是把有限的个体映射到有限的空间,以此提高算法的时空效率以这题的测试数据为例,本题的五个区间为1 4,2 6,8 10,3 4,7 10;其中10和4出现了两次,把重复的数字去除,然后排序得1 ,2,3,4,6,7,8,10,与之对应的数组下标为1 2 3 4 5 6 7 8,以数组下标区间边界得到新的五个区间为[1,4],[2,5],[7,8],[3,4],[6,8].有题目知每次区间最多给10000个,那么线段树的N = 20000.接下来就用线段树的成段更新就可以了,这里不用信息的维护

离散化的一些注意事项:
1、有n个数字ai,n一般小于10^6 ,而这些数字的范围却很大,比如 0 <= ai <= 1,000,000,000 , 先在按我们的思路要把ai当做下标
这时候要用离散化
2、ai 中没有相同的数字
如poj2299和poj2528

代码如下:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<time.h>
#include<math.h>

#define N 20000 + 5
#define inf 0x7fffffff
#define eps 1e-9
#define pi acos(-1.0)
#define P system("pause")
using namespace std;
int tree[N*4], mapp[N][2];
int x,y;
set<int> q;
struct node
{
    int val,bor;
}s[2*N];
bool cmp (node a,node b)
{
    return a.val < b.val;
}
void pushdown(int o)
{
    if(tree[o] > 0)
    {
        tree[2*o] = tree[2*o+1] = tree[o];
        tree[o] = -1;
    }
}

void update(int o,int l,int r,int k)
{
    if(x <= l && y >= r)
    {
        tree[o] = k;
    }
    else
    {
        int m = (l+r)/2;
        pushdown(o);
        if(x <= m) update(2*o,l,m,k);
        if(y > m) update(2*o+1,m+1,r,k);
    }

}
void query(int o,int l,int r)
{
    if(tree[o] > 0) {
        q.insert(tree[o]);
        return;
    }
    if(l == r) return;
    int m = (l+r)/2;
    query(2*o,l,m);
    query(2*o+1,m+1,r);
}
int main()
{
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        memset(tree,-1,sizeof(tree));
        int i;
        for(i = 0; i < n ; i++)    //离散化
        {
             scanf("%d%d",&mapp[i][0],&mapp[i][1]);
             s[2*i].val = mapp[i][0];
             s[2*i+1].val = mapp[i][1];
             s[2*i].bor = -(i+1);
             s[2*i+1].bor = i+1;
        }
        sort(s,s+2*n,cmp);
        int k = 1;
        if(s[0].bor < 0)
           mapp[-s[0].bor-1][0] = k;
        else
           mapp[s[0].bor-1][1] = k;

        for(i = 1; i < 2*n; i++)
        {
            if(s[i].val != s[i-1].val)
               k++;
            if(s[i].bor < 0)
                mapp[-s[i].bor-1][0] = k;
            else
                mapp[s[i].bor-1][1] = k;
        }
       // for(i = 0; i < n; i++)
         //  cout<<mapp[i][0]<<" "<<mapp[i][1]<<endl;


        for(i = 0; i < n; i++)//线段树成段更新
        {
             x = mapp[i][0];
             y = mapp[i][1];
             update(1, 1, k, i+1);
        }
        q.clear();
        query(1,1,k);
        printf("%d\n",q.size());
    }


    return 0;
}
/*
1
5
1 4
2 6
8 10
3 4
7 10
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值