zoukankan      html  css  js  c++  java
  • POJ2528 Mayor's poster 线段树+离散化解法

    标准解法是用的离散化。此题的特殊性在于普通离散化后,两个相邻的值之间的区间也可能是有效的区间。例如:

    有三张海报[1, 4] [5, 6][1, 6],离散化后1->1, 2->4, 3->5, 4->6。他们就会覆盖[1, 6]这张海报。
    另外三张海报[1, 3] [5, 6][1, 6],离散化后1->1, 2->3, 3->5, 4->6。他们不会覆盖[1, 6]这张海报。
    而此时两组数据的前两张海报都会变成[1, 2] [3, 4] 两个区间,都覆盖了[1,4]区间。

    解决方案是如果发现两个离散值之间的距离大于1,就在两个值之间插入一个数字。例如第二组中的3和5,他们大于1,就插入一个数,为了保证最后用二分查找的方便,插入(3 , 5)之间的任意数字都可以。

    另外最开始的时候,我采用的动态生成数组存储离散化的值,最后导致了段错误(SIGSEGV)。采取使用静态数组,并且把部分的数组移到main函数外面,就可以了。

    结果是:4476kB50ms

    可以看出,不管是时间复杂度还是空间复杂度都比插入节点建树的方案好,而且自己实现的quicksort比系统的快,只是编码量比较大

    #include <stdio.h>
    #include <string.h>
    //#include <stdlib.h>//qsort头文件
    //#include <algorithm>//sort头文件
    #include <iostream>
    using namespace std;
    struct Poster{
        int l,u;
    };
    struct InTree{
        int l,u;
        InTree *left,*right;
        int color;//-2表示该区间是混合色或者还未涂色
        InTree(int low,int upp){
            l= low; u = upp;
            left = right = 0;
            color = -2;
        }
    };
    
    InTree* Build(int low, int upp){
        InTree *root = new InTree(low,upp);
        if(low < upp){
        //递归构建左右子树,并初始化max和min值
            root->left = Build(low,(low+upp)/2);
            root->right = Build((low+upp)/2+1,upp);
        }
        return root;
    }
    
    void Update(InTree *root,int low,int upp,int c){
        if(low <= root->l && root->u <=upp){
            root->color = c;
            return;
        }
        else{
            if(root->color >= 0){//当本区间是单一色时,需要将颜色下推
                root->right->color = root->left->color = root->color;
                root->color = -2;
            }
    
            if(low <= (root->l+root->u)/2){
                Update(root->left,low,upp,c);
            }
            if(upp >= (root->l+root->u)/2 + 1){
                Update(root->right,low,upp,c);
            }
        }
    }
    
    void Query(InTree *root,bool *map){
    //查询root子树中全涂成一种颜色的区间,并将区间的颜色对应的map位置置为true
        if(root == 0)
            return;
        else if(root->color >=0)
            map[root->color] = true;
        else{
            Query(root->left,map);
            Query(root->right,map);
        }
    }
    
    void Delete(InTree *root){
    //递归删除节点
        if(root == 0)
            return;
        else{
            Delete(root->left);
            Delete(root->right);
            delete root;
        }
    }
    
    int CMP(const void *a,const void *b){
        int* ca = (int *)a;
        int* cb = (int *)b;
        if(*ca > *cb)return 1;
        if(*ca < *cb)return -1;
        if(*ca==*cb)return 0;
    }
    
    int BinarySearch(int *a,int n,int key){
        int l = 1,u = n;
        while(l<=u){
            int mid = l+(u-l)/2;
            if(a[mid] == key)
                return mid;
            else if(a[mid]<key)l = mid +1;
            else u = mid - 1;
        }
        return -1;
    }
    
    int Partition(int *pos,int n){
        int p = pos[0];
        int i=0,j=n;
        while(true){
            while(pos[++i]< p && i<n-1);
            while(pos[--j]> p);
            if(i>=j)break;
            else{
                int t = pos[i];
                pos[i] = pos[j];
                pos[j] = t;
            }
        }
        pos[0] = pos[j];
        pos[j] = p;
        return j;
    }
    
    void Quicksort(int *pos,int n){
        if(n>1){
            int i = Partition(pos,n);
            Quicksort(pos,i);
            Quicksort(pos+i+1,n-i-1);
        }
    }
    
    //如果把这两个数组写在main函数中,会出现rte的错误。估计是代码段容量不够。同理如果都写成new形式,也会容量不够
    int pos[10010*2];
    int indexs[10010*3];//最多3*n个位置(用index做名字会出错)
    
    int main(){
        int c;
        int n;
        //int pos[10010*2];
        //int indexs[10010*3];//最多3*n个位置(用index做名字会出错)
        bool map[10010];
        Poster posters[10010];
        scanf("%d",&c);
        while(c>0){
            --c;
            scanf("%d",&n);
            //printf("n=%d;",n);
            int l,u;
            for(int i=0;i<n;i++){
                scanf("%d%d",&l,&u);
                pos[2*i] = posters[i].l = l;
                pos[2*i+1] = posters[i].u = u;
                //printf("l=%d;u=%d;\n",l,u);
            }
            //离散化端点值为排序后的下标
            //qsort(pos,2*n,sizeof(int),CMP);
            //sort(pos,pos+2*n);
            Quicksort(pos,2*n);
            //整理端点值,把相等的保留一个,把不相邻的两个端点之间插一个任意数
            int cnt = 0;//在indexs数组中记录从indexs[1]开始,cnt标识前一个有效位置
            indexs[++cnt]=pos[0];
            for(int i = 1;i<2*n;i++){
                if(pos[i] != indexs[cnt]){
                    if(pos[i] > indexs[cnt]+1){//大于1,需要插入一个节点
                        indexs[++cnt] = pos[i]-1;
                    }
                    indexs[++cnt] = pos[i];
                }
            }
    
            //重新调整poster的端点坐标到[1,cnt]的区间
            for(int i=0;i<n;i++){
                posters[i].l = BinarySearch(indexs,cnt,posters[i].l);
                posters[i].u = BinarySearch(indexs,cnt,posters[i].u);
            }
            //建树
            InTree* root = Build(1,cnt);
            //更新数据
            for(int i=0;i<n;i++){
                Update(root,posters[i].l,posters[i].u,i);
            }
            //查询
            memset(map,false,10010*sizeof(bool));
            Query(root,map);
            //统计结果
            cnt=0;
            for(int i=0;i<n;i++){
                if(map[i])cnt++;
            }
            printf("%d\n",cnt);
            //删树
            Delete(root);
        }
        return 0;
    }



  • 相关阅读:
    json对象和字符串的相互转换
    使用link rel="shortcut icon"为网页标题加图标
    jQuery——Js与jQuery的相互转换
    用accessKey设置快捷键
    CSS :invalid 选择器
    创建并调用 DLL(1)
    调用外部 DLL 中的函数(2. 晚绑定)
    调用外部 DLL 中的函数(1. 早绑定)
    VCL 中的 Windows API 函数(6): BeginDeferWindowPos
    VCL 中的 Windows API 函数(5): AlphaBlend
  • 原文地址:https://www.cnblogs.com/zhuyuanhao/p/3262859.html
Copyright © 2011-2022 走看看