POJ-2585-Mayor's posters-成段更新+(hash)离散化思想

题目链接:http://poj.org/problem?id=2528

这个题目是很经典的离散化成段更新线段树问题,可以试着多做几次,充分理解;

转自:http://www.notonlysuccess.com/index.php/segment-tree-complete/

题意:在墙上贴海报,海报可以互相覆盖,问最后可以看见几张海报
思路:这题数据范围很大,直接搞超时+超内存,需要离散化:
离散化简单的来说就是只取我们需要的值来用,比如说区间[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,2,6,10]
如果相邻数字间距大于1的话,在其中加上任意一个数字,比如加成[1,2,3,6,7,10],然后再做线段树就好了.
线段树功能:update:成段替换 query:简单hash

好吧,现在这个代码只能过poj的数据,并不是真正的完美。。。不知为何一直RE,欢迎指点;

#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
#include<queue>
#include<map>
#include<cmath>
#include<stack>
#include<set>
#include<vector>
#include<algorithm>
#define LL long long
using namespace std;
//  照着题目数组开10005,给报RE,坑啊;
int pos[100005][2];  //  用于离散化,存离散化后区间的左右节点;
bool vis[100005];
int ans,mm;         //  ans用于统计最后结构,mm表示第几张海报;
struct node1        //  用于离散化的结构体;
{
    int p,n;        //  p存节点,n存第几张海报;
}Line[100005<<1];
struct node2        //  线段树结构体;
{
    int l,r,c;
}node[100005<<2];
bool cmp(node1 x,node1 y)   //  按左节点递增排序;
{
    return x.p<y.p;
}
void build(int l,int r,int rt)  //  建树;
{
    node[rt].l=l;
    node[rt].r=r;
    node[rt].c=0;           //  染色标记;
    if(l!=r){
        int mid=(l+r)>>1;
        build(l,mid,rt<<1);
        build(mid+1,r,rt<<1|1);
    }
}
void Insert(int l,int r,int c,int rt)   //  更新;
{
    if(node[rt].l==l&&node[rt].r==r){
        node[rt].c=c;
        return;
    }
    if(node[rt].c>0&&node[rt].c!=c){    //  说明得更新下一个节点,相当于我之前写的PushDown;
        node[rt<<1].c=node[rt].c;
        node[rt<<1|1].c=node[rt].c;
        node[rt].c=0;
    }
    int mid=(node[rt].l+node[rt].r)>>1;
    if(r<=mid) Insert(l,r,c,rt<<1);
    else if(l>mid) Insert(l,r,c,rt<<1|1);
    else{
        Insert(l,mid,c,rt<<1);
        Insert(mid+1,r,c,rt<<1|1);
    }
}
void query(int rt)                  //  区间查询;
{
    if(node[rt].c!=0){
        if(!vis[node[rt].c]){       //  统计被染了多少种不同的颜色;
            ans++;
            vis[node[rt].c]=true;
        }
        return;
    }
    query(rt<<1);
    query(rt<<1|1);
}
int main()
{
    int t,n,a,b;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i=0;i<n;i++){
            scanf("%d%d",&a,&b);    //  将a,b区间的长度离散成更小的区间
            Line[i<<1].p=a;
            Line[i<<1|1].p=b;
            Line[i<<1].n=-(i+1);    //  用负数表示左节点;
            Line[i<<1|1].n=i+1;     //  用正数表示右节点;
        }
        sort(Line,Line+2*n,cmp);    //  排序;
        int temp=Line[0].p; mm=1;
        for(int i=0;i<2*n;i++){
            if(Line[i].p!=temp){
                mm++;
                temp=Line[i].p;
            }
            //if(i>0&&Line[i].p>(Line[i-1].p+1)) mm++;   这条语句其实是我想解决离散化bug的,可是结果却一直RE,导致只过了POJ的较弱数据;
            if(Line[i].n<0) pos[-Line[i].n-1][0]=mm;
            else pos[Line[i].n-1][1]=mm;
        }
        build(1,mm,1);
        for(int i=0;i<n;i++){
            Insert(pos[i][0],pos[i][1],i+1,1);
        }
        memset(vis,false,sizeof(vis));
        ans=0;
        query(1);
        printf("%d\n",ans);
    }
    return 0;
}


 

你可能感兴趣的:(hash,离散化,Posters,POJ2585,Mayors,线段树成段更新)