POJ2528,线段树+离散化

本文深入分析了POJ2528 Mayor'sposters问题,详细介绍了输入输出规范,题意解读,以及采用线段树结合离散化技巧解决方法。通过实例演示,清晰阐述了如何统计可见海报数量,提供了完整代码实现,旨在帮助读者理解并解决类似问题。

题目链接:

POJ2528

Mayor's posters
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 50574 Accepted: 14658

Description

The citizens of Bytetown, AB, could not stand that the candidates in the mayoral election campaign have been placing their electoral posters at all places at their whim. The city council has finally decided to build an electoral wall for placing the posters and introduce the following rules:
  • Every candidate can place exactly one poster on the wall.
  • All posters are of the same height equal to the height of the wall; the width of a poster can be any integer number of bytes (byte is the unit of length in Bytetown).
  • The wall is divided into segments and the width of each segment is one byte.
  • Each poster must completely cover a contiguous number of wall segments.

They have built a wall 10000000 bytes long (such that there is enough place for all candidates). When the electoral campaign was restarted, the candidates were placing their posters on the wall and their posters differed widely in width. Moreover, the candidates started placing their posters on wall segments already occupied by other posters. Everyone in Bytetown was curious whose posters will be visible (entirely or in part) on the last day before elections.
Your task is to find the number of visible posters when all the posters are placed given the information about posters' size, their place and order of placement on the electoral wall.

Input

The first line of input contains a number c giving the number of cases that follow. The first line of data for a single case contains number 1 <= n <= 10000. The subsequent n lines describe the posters in the order in which they were placed. The i-th line among the n lines contains two integer numbers l i and ri which are the number of the wall segment occupied by the left end and the right end of the i-th poster, respectively. We know that for each 1 <= i <= n, 1 <= l i <= ri <= 10000000. After the i-th poster is placed, it entirely covers all wall segments numbered l i, l i+1 ,... , ri.

Output

For each input data set print the number of visible posters after all the posters are placed.

The picture below illustrates the case of the sample input.

Sample Input

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

Sample Output

4
 
题意:
候选者在展览板上贴海报,当所有人都贴完了,有多少海报是可以被看见的(看见,可以是整幅海报都可以被看见,或者是海报的一部分可以被看见)
 
题解:
我觉得这道题目需要注意的是,(拿样例来说)区间[1,4],1和4不是点(可以看图)是某一块小展览板;
在离散化的时候,需要注意:(看不懂下面的话,可以先看程序,手推一组样例,然后再来理解这段话)
1 3 4 5 9
一般程序对应于
1 2 3 4 5(这样会导致不相邻的线段变为相邻)
实际应该对应于
1 3 4 5 7
线段树+离散化 就OK了
//bei
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define Maxn 12000

int tol[Maxn<<4],segT[Maxn<<4],li[Maxn],ri[Maxn];
//tol是用来保存所有区间的左右端点,segT是建树用的数组,li是保存区间左端点,ri是保存对应右端点
bool vis[Maxn]; //用来标记哪些颜色已经统计过了
int ans;

int Binsearch(int key,int r,int tol[]) //二分查找位置,返回的位置就是离散化后的值
{
    int l = 1,m;
    while (l <= r)
    {
        m = (l+r) >> 1;
        if (tol[m] > key)
            r = m - 1;
        else if (tol[m] < key)
            l = m + 1;
        else
            return m;
    }
}

void PushDown(int rt) // 线段树的延迟更新
{
    if (segT[rt])
    {
        segT[rt<<1] = segT[rt<<1|1] = segT[rt];
        segT[rt] = 0;
    }
}

void update(int L,int R,int color,int l,int r,int rt) // 将对应区间的值更新为color,表示该段区间贴的海报
{
    if (L <= l && r <= R)
    {
        segT[rt] = color;
        return ;
    }
    PushDown(rt); // 当该区间被贴上另外的海报时,需要向下更新!
    int m = (l+r) >> 1;
    if (L <= m)
        update(L,R,color,lson);
    if (R > m)
        update(L,R,color,rson);
}

void query(int l,int r,int rt)
{
    if (segT[rt])
// 举个例子:区间[4,6]贴的是同一幅海报,假设对应color的值为2,在线段树中[4,6] 是两段区间[4,5]和[6],当统计完[4,5]之后,再统计到[6]时就不能在加一了
//所以得用一个vis数组用来标记哪些颜色已经被统计过了
    {
        if (!vis[segT[rt]])
        {
            ++ans;
            vis[segT[rt]] = true;
        }
        return ;
    }
    if (l == r) return ;
    int m = (l+r) >> 1;
    query(lson);
    query(rson);
}

int main()
{
    int c,n,i,k;
    while (~scanf("%d",&c))
    {
        while (c--)
        {
            scanf("%d",&n);
            k = 1;
            for (i = 1; i <= n; ++i) // tol数组先保存所有区间的端点值
            {
                scanf("%d%d",&li[i],&ri[i]);
                tol[k++] = li[i];
                tol[k++] = ri[i];
            }
            sort(tol+1,tol+k); // 排序
            int m = 2;
            for (i = 2; i < k; ++i) // 去掉tol数组中重复的值,因为在二分查找位置时,不能一个值可以映射成两个位置,对吧!
            {
                if (tol[i] != tol[i-1])
                    tol[m++] = tol[i];
            }
            for (i = m - 1; i > 1; --i)//这步+下面的排序一起理解,目的是将原本不相邻的区间也离散成不相邻的区间(可以手推一组样例,就好理解了)
            {
                if (tol[i] != tol[i-1]+1)
                    tol[m++] = tol[i-1] + 1;
            }
            sort(tol+1,tol+m);
            memset(segT,0,sizeof(segT));
            for (i = 1; i <= n; ++i)
            {
                int a = Binsearch(li[i],m-1,tol);//得到该区间左端点离散后的值
                int b = Binsearch(ri[i],m-1,tol);
                update(a,b,i,1,m-1,1);//建树,其中这段区间对应的海报color值为i,正好保证了每幅海报是不相同的
            }
            ans = 0;
            memset(vis,false,sizeof(vis));
            query(1,m-1,1); //查询,记得写上上面两条语句;
            printf("%d\n",ans);
        }
    }
    return 0;
}

内容概要:本文详细记录了对一个Android ARM64静态ELF文件中字符串加密机制的逆向分析过程。该ELF文件的所有字符串均被加密,无法通过常规strings命令或IDA直接识别。作者通过分析发现,加密字符串存储在.rodata段,其解密所需信息(包括密文地址、长度和16位密钥)保存在.data.rel.ro段的40字节描述符中。核心解密函数sub_10F408采用自反的双pass流密码算法,结合固定密钥KEY_TERM(由.data段24字节数据计算得出),实现字节级非线性、位置与长度相关的加密。文章还复现了完整的Python解密脚本,并揭示了该保护机制的本质为代码混淆而非强加密,最终成功批量解密全部956条字符串,暴露程序真实行为,如shell命令模板、设备标识篡改、网络重置等操作。此外,文中还提及未启用的自定义壳框架及其反dump设计。; 适合人群:具备逆向工程基础的安全研究人员、二进制分析人员及对ELF保护技术感兴趣的开发者。; 使用场景及目标:①学习ELF二进制中字符串加密的典型实现方式与逆向突破口;②掌握从结构识别、函数追踪到算法还原的完整逆向流程;③理解“绑定二进制”的完整性校验设计及其局限性;④实践编写IDAPython脚本自动化提取与解密敏感数据。; 阅读建议:此资源以实战案例驱动,不仅展示技术细节,更强调逆向思维与验证方法,建议读者结合IDA调试环境,逐步跟随文中步骤进行动态分析与算法验证,深入理解每一步的推理依据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值