POJ_2528 Mayor's poster(线段树+离散化)

来源:互联网 发布:世界网络多少年了 编辑:程序博客网 时间:2024/06/06 07:01

题目请点我
题解:
这道题与之前的题目相比重点在于一个映射的预处理,题目所给的区间达到10000000,而最多只有10000个点,如果直接建树的话太过于空旷。把这些区间的左右节点一一对应,最多有4×10000个点,远小于之前的10000000,而且区间之间的对应关系也不会改变。

举个例子:
区间:[2,6],[4,8],[6,10]
我们进行下面对应:
2 4 6 8 10
1 2 3 4 5
则原区间变为[1,3],[2,4],[3,5]。可以发现它们之间的覆盖关系并没有改变,但是却紧凑了很多。
但是注意对应后,应该有一个去重的操作,防止出错。

还有一点去需要注意,区间的对应稍不注意会出现颜色丢失的情况,如下:
[1,10],–[1,4],–[6,10]
当我们手工模拟会发现,我们只是对1,4,6,10,进行了对应,即1,2,3,4,原集合中的4,6被视为了相邻元素,所以5处的颜色丢失,最终得到了错误的结果。
为了防止发生这种情况我们进行插值,在两个不相邻的节点间插入无关值,但是能有效的避免这种情况。

数组范围分析,10000个区间对应最多20000个节点,再进行插值后得到最多40000+个节点,对应segTree数组达到4×40000+。

而线段树部分实现起来就比较简单了,lazy标记一下,最后统计仍可见的不同颜色就可以了。

参考博客

代码实现:

#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>#define MAX 20010#define LCHILD root<<1,l,mid#define RCHILD root<<1|1,mid+1,r#define MID(x,y) (x+y)>>1using namespace std;int T;int N;int mm[MAX<<2];int show[MAX<<3];int L[MAX],R[MAX];int segTree[MAX<<3];void pushdown(int root);int query(int root,int l,int r,int a,int b);void update(int root,int l,int r,int a,int b,int flag);int main(){    scanf("%d",&T);    while( T-- ){        scanf("%d",&N);        int pos = 1;        int tmp = 2;        //注意show[0]要提前标记为1        memset(segTree,0,sizeof(segTree));        memset(show,0,sizeof(show));show[0] = 1;        for( int i = 1; i <= N; i++ ){            scanf("%d%d",&L[i],&R[i]);            mm[pos++] = L[i];            mm[pos++] = R[i];        }        //去重操作        sort(mm+1,mm+pos);        for( int i = 2; i < pos; i++ ){            if( mm[i] != mm[i-1] ){                mm[tmp++] = mm[i];            }        }        //插值        pos = tmp;        for( int i = pos-1; i > 1; i-- ){            if( mm[i] != mm[i-1]+1 ){                mm[pos++] = mm[i-1]+1;            }        }        sort(mm+1,mm+pos);        //lowe_bound找到a,b位置        for( int i = 1; i <= N; i++ ){            int a,b;            a = lower_bound(mm+1,mm+pos,L[i])-mm;            b = lower_bound(mm+1,mm+pos,R[i])-mm;            update(1,1,pos-1,a,b,i);        }        int res = query(1,1,pos-1,1,pos-1);        printf("%d\n",res);    }    return 0;}void update(int root,int l,int r,int a,int b,int flag){    if( a > r || b < l ){        return ;    }    if( a <= l && r <= b ){        segTree[root] = flag;        return ;    }    if( segTree[root] != 0 ){        pushdown(root);    }    int mid = MID(l,r);    update(LCHILD,a,b,flag);    update(RCHILD,a,b,flag);    return ;}int query(int root,int l,int r,int a,int b){    if( a > r || b < l ){        return 0;    }    //该区间属于同一种颜色,show数组标记是否已被统计    if( segTree[root]!= 0 ){        if( show[segTree[root]] != 1 ){            show[segTree[root]] = 1;            return 1;        }        return 0;    }    //未标色的叶子节点    if( l == r ){        return 0;    }    int mid = MID(l,r);    return query(LCHILD,a,b)+query(RCHILD,a,b);}void pushdown(int root){    segTree[root<<1] = segTree[root];    segTree[root<<1|1] = segTree[root];    segTree[root] = 0;    return ;}
0 0