POJ2528 Mayor's posters(线段树成段替换,区间查询,离散化简单hash)

题意:在墙上贴海报,海报可以互相覆盖,问最后可以看见几张海报
思路:这题数据范围很大,直接搞超时+超内存,需要离散化:
离散化简单的来说就是只取我们需要的值来
用,比如说区间[1000,2000],[1990,2012]
我们用不到[-∞,999][1001,1989][1991,1999][2001,2011][2013,+∞]这些值,所以我只需要
1000,1990,2000,2012就够了,将其分别映射到0,1,2,3,在于复杂度就大大的降下来了
所以离散化要保存所有需要用到的值,排序后,分别映射到1~n,这样复杂度就会小很多很多
而这题的难点在于每个数字其实表示的是一个单位长度(并非一个点),这样普通的离散化会造成许多错误(包括我以前的代码,poj这题数据奇弱)
给出下面两个简单的例子应该能体现普通离散化的缺陷:
例子一:1-10 1-4 5-10
例子二:1-10 1-4 6-10
普通离散化后都变成了[1,4][1,2][3,4]
线段2覆盖了[1,2],线段3覆盖了[3,4],那么线段1是否被完全覆盖掉了呢?
例子一是完全被覆盖掉了,而例子二没有被覆盖

为了解决这种缺陷,我们可以在排序后的数组上加些处理,比如说[1,2,6,10]
如果相邻数字间距大于1的话,在其中加上任意一个数字,比如加成[1,2,3,6,7,10],然后再做线段树就好了.
线段树功能:update:成段替换 query:简单hash

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <cmath>
#include <algorithm>
using namespace std;
#define M 11111
#define ls node<<1,l,m
#define rs node<<1|1,m+1,r
int n,cnt;
bool hash[M];
int li[M],ri[M],X[M*3];
int tree[M<<4];
int Bin(int key,int n,int X[])
{
    int l=0,r=n-1;
    while(l<=r)
    {
        int m=(l+r)>>1;
        if(X[m]==key) return m;
        if(X[m]<key) l=m+1;
        else r=m-1;
    }
    return -1;
}
void pushdown(int node)
{
    if(tree[node]!=-1)
    {
        tree[node<<1]=tree[node<<1|1]=tree[node];
        tree[node]=-1;
    }
}
void update(int node,int l,int r,int L,int R,int c)
{
    if(L<=l&&r<=R)
    {
        tree[node]=c;
        return ;
    }
    pushdown(node);
    int m=(l+r)>>1;
    if(L<=m) update(ls,L,R,c);
    if(m<R) update(rs,L,R,c);
}
void query(int node,int l,int r)
{
    if(tree[node]!=-1)
    {
        if(!hash[tree[node]]) cnt++;
        hash[tree[node]]=true;
        return ;
    }
    if(l==r) return;
    int m=(l+r)>>1;
    query(ls);
    query(rs);
}
int main()
{
    //freopen("in.txt","r",stdin);
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        int nn=0;
        for(int i=0;i<n;i++)
        {
            scanf("%d%d",&li[i],&ri[i]);
            X[nn++]=li[i];
            X[nn++]=ri[i];
        }
        sort(X,X+nn);
        int m=1;
        for(int i=1;i<nn;i++)
        {
            if(X[i]!=X[i-1]) X[m++]=X[i];
        }
        for(int i=m-1;i>0;i--)
        {
            if(X[i]!=X[i-1]+1) X[m++]=X[i-1]+1;
        }
        sort(X,X+m);
        memset(tree,-1,sizeof(tree));
        for(int i=0;i<n;i++)
        {
            int l=Bin(li[i],m,X);
            int r=Bin(ri[i],m,X);
            update(1,0,m,l,r,i);
        }
        cnt=0;
        memset(hash,false,sizeof(hash));
        query(1,0,m);
        printf("%d\n",cnt);
    }
    return 0;
}

POJ2528 Mayor's posters(线段树成段替换,区间查询,离散化简单hash)

时间: 2024-10-17 08:00:50

POJ2528 Mayor's posters(线段树成段替换,区间查询,离散化简单hash)的相关文章

POJ 2528 Mayor&#39;s posters 线段树成段更新+离散化

题目来源:POJ 2528 Mayor's posters 题意:很多张海报贴在墙上 求可以看到几张海报 看那两张图就行了 第一张俯视图 思路:最多2W个不同的数 离散化一下 然后成段更新 a[rt] = i代表这个区间是第i张报纸 更新玩之后一次query cover[i]=1代表可以看到第i张报纸 #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const

POJ训练计划2528_Mayor&#39;s posters(线段树/成段更新+离散化)

解题报告 地址传送门 题意: 一些海报,覆盖上去后还能看到几张. 思路: 第一道离散化的题. 离散化的意思就是区间压缩然后映射. 给你这么几个区间[1,300000],[3,5],[6,10],[4,9] 区间左右坐标排序完就是 1,3,4,5,6,9,10,300000; 1,2,3,4,5,6, 7 ,8; 我们可以把上面的区间映射成[1,8],[2,4],[5,7],[3,6]; 这样就节省了很多空间. 给线段染色, lz标记颜色. #include <map> #include <

POJ训练计划2528_Mayor&amp;#39;s posters(线段树/成段更新+离散化)

解题报告 id=2528">地址传送门 题意: 一些海报,覆盖上去后还能看到几张. 思路: 第一道离散化的题. 离散化的意思就是区间压缩然后映射. 给你这么几个区间[1,300000],[3,5],[6,10],[4,9] 区间左右坐标排序完就是 1,3,4,5,6,9,10,300000; 1,2,3,4,5,6, 7 ,8; 我们能够把上面的区间映射成[1,8],[2,4],[5,7],[3,6]; 这样就节省了非常多空间. 给线段染色, lz标记颜色. #include <ma

poj-----(2528)Mayor&#39;s posters(线段树区间更新及区间统计+离散化)

Mayor's posters Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 43507   Accepted: 12693 Description The citizens of Bytetown, AB, could not stand that the candidates in the mayoral election campaign have been placing their electoral post

POJ 2528 Mayor&#39;s posters (hash+线段树成段更新)

题意:有一面墙,被等分为1QW份,一份的宽度为一个单位宽度.现在往墙上贴N张海报,每张海报的宽度是任意的,但是必定是单位宽度的整数倍,且<=1QW.后贴的海报若与先贴的海报有交集,后贴的海报必定会全部或局部覆盖先贴的海报.现在给出每张海报所贴的位置(左端位置和右端位置),问张贴完N张海报后,还能看见多少张海报?(PS:看见一部分也算看到.) 思路:简单的成段更新,但是数据量是1千万,会MT,所以要区间压缩(离散化),保证覆盖的关系不变,离散化的时候有个易错的细节,poj数据水了,这个易错点引用h

Mayor&#39;s posters(线段树之点的成段更新加离散化)

bin神的萌萌哒专题 这道题目也是简单区间更新的线段树题目,不过题目的数据范围很大,直接搞,时间空间的花费都会异常的高,所以就要用到离散化来优化时间空间复杂度. 何为离散化?........................ 简单地说就是对于给出的庞大数据进行一种数据上的缩小. 比如给你一段(1,10000)的区间,由于我们要的不是其区间长度,我们只需要知道这段区间的状态 如何,于是我们可以忽视其长度,把其表示成(1,2)这个区间长度极小的区间,这相当于物理上的质点. 当我们处理的问题上与其区间长

poj 2528 Mayor&#39;s posters(线段树)

题目链接:http://poj.org/problem?id=2528 思路分析:线段树处理区间覆盖问题,也可以看做每次给一段区间染不同的颜色,最后求在整段区间上含有的所有颜色种类数: 注意由于区间太大,所以需要离散化: 区间更新:对于线段树的每个结点,标记颜色,初始时没有颜色,标记为0:当更新时,使用延迟标记,需要标记传递到子节点: 区间查询:使用深度优先查询线段树,当某个子节点的颜色不为0时,即停止深度优先搜索,并在map中查询是否已经记录该段区间的颜色: 代码如下: #include <i

Mayor&#39;s posters 线段树区间覆盖

题目链接 http://poj.org/problem?id=2528 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 dec

Codeforces Round #149 (Div. 2) E. XOR on Segment (线段树成段更新+二进制)

题目链接:http://codeforces.com/problemset/problem/242/E 给你n个数,m个操作,操作1是查询l到r之间的和,操作2是将l到r之间的每个数xor与x. 这题是线段树成段更新,但是不能直接更新,不然只能一个数一个数更新.这样只能把每个数存到一个数组中,长度大概是20吧,然后模拟二进制的位操作.仔细一点就行了. 1 #include <iostream> 2 #include <cstdio> 3 #include <cmath>