线段树专题 线段树+离散化

题目链接:http://poj.org/problem?id=3468
题目大意:有一个长为10000000的墙,有1 <= n <= 10000个市长候选人去张贴海报,每个人的海报长度不限。上面的海报会覆盖下面的海报,问你最后能看见哪些海报。
线段树专题 线段树+离散化_第1张图片
线段树专题 线段树+离散化_第2张图片
思路:这个用线段树add标记维护当前区间的海报就行了,然后就MLE了。两个40000000的数组开不下。于是就必须优化。因为候选人只有10000个,如果把长度离散化一下就可以了,因为会不会覆盖只与两张长度的大小关系有关,而并不用保存具体长度大小。
例如:一张海报是1 - 10000,另外一张是2-5000000,可以把长度离散为1-3, 2-4。把所有海报的端点的相对大小关系保存下来就可以了。
只有如果每张海报的端点都不同,也只需要2*n个节点就行了。
还有查找的时候,只有查找当前区间的add[i]!=0就可以了。说明这个区间最上面就是这张海报。

思考:离散化, 区间的查找。

#include
#include
#include
#include 
#include 
#include 
#define ll long long
using namespace std;

#define MAX_NODE 800005
#define MAX_ 200005

struct NODE
{
    int l, r;

}node[MAX_NODE];
int add[MAX_NODE];
set<int> s;
void BT(int i, int l ,int r)   //建树
{
    node[i].l=l;
    node[i].r=r;
    if(l==r)                   //根节点
    {
        return;
    }
    BT((i<<1), l, (l+r)/2);    //建左子树
    BT((i<<1)+1, (l+r)/2+1, r);//建右子树

}

int m=0;
void upadd(int i)
{
    if(add[i])
    {
        add[i<<1]=add[i];          //把左右子的add标记进行更新
        add[(i<<1)+1]=add[i];

        add[i]=0;                   //清零父节点的add标记
    }
}

void UP(int i, int l, int r, int c)//更新
{
    if(node[i].l==l&&node[i].r==r)//找到更新区间
    {
        add[i]=c;                //更新add标记

        return;
    }

    if(node[i].l==node[i].r)      //叶子节点
    {
        add[i]=c;
        return;
    }

    upadd(i);                     //把此本节点的add往下移动

    int mid=(node[i].l+node[i].r)/2;//继续寻找区间
    if(r<=mid)                    //全在左区间
    {
        UP(i<<1, l, r, c);
    }
    else if(l>mid)                //全在右区间
    {
        UP((i<<1)+1, l, r, c);
    }
    else
    {
        UP(i<<1, l, mid, c);
        UP((i<<1)+1, mid+1, r, c);
    }

}

void FD(int i, int l, int r)   //查找
{
    if(add[i]!=0)
    {
        s.insert(add[i]);
        return;
    }
    if(l==r)
    {
        return;
    }
    FD(i<<1, l, (l+r)/2);
    FD((i<<1)+1, (l+r)/2+1, r);

}
//建树 BT(1, 1 ,n);节点1-n
//查询 FD(1, a, b);[a, b]的信息
//更新 UP(1, a, b, c);//把区间的add+=a

int c[20005], p=0;
int ls[20005];

void lsh()
{
    sort(c, c+p);
    int cnt=unique(c, c+p)-c;

    for(int i=0;i<p;i++)
        ls[i]=lower_bound(c, c+cnt, ls[i])-c+1;

}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        memset(add, 0, sizeof(add));
        p=0;
        s.clear();
        int n;
        scanf("%d",&n);
        BT(1, 1, 200005);
        for(int i=1;i<=n;i++)
        {
            int a, b;
            scanf("%d%d",&a,&b);
            ls[p]=a, c[p++]=a;
            ls[p]=b, c[p++]=b;

        }
        lsh();                        //离散化
        for(int i=1;i<p;i+=2)
        {
            UP(1, ls[i-1], ls[i], i); //更新
        }
        FD(1, 1, 200005);
        printf("%d\n",s.size());

    }

    return 0;
}

你可能感兴趣的:(线段树)