• POJ 2528 Mayor's posters 线段树+离散化


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

    题意: 有长度为 10000000 的一堵墙, n个市长按照先后顺序在 L 到 R 区间之间张贴海报,问最后能看见几个人的海报, 后面的海报会覆盖掉前面的海报.

    先了解一下离散化吧(传送门):

    有些数据本身很大, 自身无法作为数组的下标保存对应的属性。

    如果这时只是需要这堆数据的相对属性, 那么可以对其进行离散化处理!

    离散化:当数据只与它们之间的相对大小有关,而与具体是多少无关时,可以进行离散化。

    例如

    9 1 0 5 4 与 5 2 1 4 3 的逆序对个数相同。
    设有4个数:
    1234567、123456789、12345678、123456
    排序:123456<1234567<12345678<123456789
               =>     1     <        2       <        3       <        4
    那么这4个数可以表示成:2、4、3、1

    使用STL算法离散化:
    思路:先排序,再删除重复元素,然后就是索引元素离散化后对应的值。
    假定待离散化的序列为a[n],b[n]是序列a[n]的一个副本,则对应以上三步为:

    sort(sub_a,sub_a+n);
    int size=unique(sub_a,sub_a+n)-sub_a;//size为离散化后元素个数
    for(i=0;i<n;i++)
    	a[i]=lower_bound(sub_a,sub_a+size,a[i])-sub_a + 1;//k为b[i]经离散化后对应的值

    对于第3步,若离散化后序列为0, 1, 2, ..., size - 1则用lower_bound,从1, 2, 3, ..., size则用upper_bound,其中lower_bound返回第1个不小于b[i]的值的指针,而upper_bound返回第1个大于b[i]的值的指针,当然在这个题中也可以用lower_bound然后再加1得到与upper_bound相同结果,两者都是针对以排好序列。使用STL离散化大大减少了代码量且结构相当清晰。

     

    解题思路:

    观察 墙的长度 是 10000000, 询问是有 10000 个, 每次询问有两个节点,也就是有10000 * 2个节点,如果按长度建立线段树, 会MLE(试过了~~~~(>_<)~~~~ ),所以应该按照节点数建立线段树, 但是要把节点离散化,建立一个映射关系. 因为节点的大小是在 10000000 以内的.

    线段树的区间更新和查询;

    先把这 2 * n 个节点 按照 从小到大顺序 排序, 建立映射, 在 更新树 更新的节点 是映射之后的小区间的节点.

    方案一: 对 falg 数组排序,下面在通过 二分查找, 找到 这个结点在 已排好序的flag数组的下标, 这个下标就是他的映射;

    方案二: 用 hash 数组 存下标,不用查找了,但是这个方法即浪费内存,也耗时,没有二分快.------------当然还有其他很多方法,比如map等等

    代码1 1176K 235MS

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    
    #define maxm 20005
    struct Tree
    {
    	int left, right, num;
    }node[maxm << 2];
    
    struct A
    {
    	int l, r;
    }a[maxm];
    
    int hash[maxm], ans = 0, flag[maxm];
    
    void BuildTree(int i, int l, int r);
    
    void Update(int i, int num, int l, int r);
    
    void PushDown(int i);
    
    void Query(int i);
    
    int Find(int num , int l , int r);
    
    int main()
    {
    	int t, n, i, j, x, y;
    	scanf("%d", &t);
    	while(t--)
    	{
    		scanf("%d", &n);
    
    		for(i = 1; i <= n; i++)
    		{
    			scanf("%d %d", &a[i].l, &a[i].r);
    			flag[2*i-1] = a[i].l , flag[2*i] = a[i].r;
    		}
    		sort(flag + 1 , flag + 2*n + 1);
    
    		BuildTree(1, 1, maxm);
    		for(i = 1; i <= n; i++)
    		{
    			x = Find(a[i].l , 1 , 2*n);
    		    y = Find(a[i].r , 1 , 2*n);
    			Update(1, i, x, y);
    		}
    		memset(hash, 0, sizeof(hash));
    		ans = 0;
    		Query(1);
    		printf("%d
    ", ans);
    	}
    }
    
    void BuildTree(int i, int l, int r)
    {
    	node[i].left = l;
    	node[i].right = r;
    	node[i].num = 0;
    	if(l == r) return;
    	int mid = (l + r) >> 1;
    	BuildTree(i << 1, l, mid);
    	BuildTree(i << 1 | 1, mid + 1, r);
    }
    
    void Update(int i, int num, int l, int r)
    {
    	if(node[i].left == l && node[i].right == r)
    	{
    		node[i].num = num;
    		return;
    	}
    	if(node[i].num != -1)
    	{
    		PushDown(i);
    		node[i].num = -1;
    	}
    	int mid = (node[i].left + node[i].right) >> 1;
    	if(r <= mid) Update(i << 1, num, l, r);
    	else if(l > mid) Update(i << 1 | 1, num, l, r);
    	else
    	{
    		Update(i << 1, num, l, mid);
    		Update(i << 1 | 1, num, mid + 1, r);
    	}
    
    }
    
    void PushDown(int i)
    {
    	node[i << 1].num = node[i << 1 | 1].num = node[i].num;
    }
    
    void Query(int i)
    {
    	if(node[i].num != -1)
    	{
    		if(node[i].num > 0 && hash[node[i].num] == 0)
    		{
    			hash[node[i].num] = 1;
    			ans++;
    		}
    		return;
    	}
    	else
    	{
    		Query(i << 1);
    		Query(i << 1 | 1);
    	}
    }
    
    int Find(int num , int l , int r)
    {
        if(l > r) return 0;
        int mid = (l + r) >> 1;
        if(flag[mid] == num)
    	{
            int i = mid - 1;
            for( ; i > 0 ; --i)
            {
                if(flag[i] != num) break;
            }
            return i + 1;
        }
        if(flag[mid] < num) return Find(num , mid + 1 , r);
        else return Find(num , l , mid - 1);
    }
    

    代码2: 哈希,40272K 625MS

    //Author LJH
    //www.cnblogs.com/tenlee
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <cmath>
    #include <algorithm>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <map>
    #define clc(a, b) memset(a, b, sizeof(a))
    #define LL long long
    using namespace std;
    
    const int inf = 0x3f;
    const int INF = 0x3f3f3f3f;
    const int maxn = 2e4+5;
    const int maxm = 1e7+5;
    
    struct Node
    {
        int l, r;
        int num;
    }tree[maxn << 2];
    
    struct Post
    {
        int l, r;
    }post[maxn];
    
    int ha[maxm], ans = 0, flag[maxn]; 
    
    void BuildTree(int i, int l, int r);
    
    void Update(int i, int num, int l, int r);
    
    void PushDown(int i);
    
    void Query(int i);
    
    int main()
    {
    	int t, n, i, j, x, y;
    	scanf("%d", &t);
    	while(t--)
    	{
    		scanf("%d", &n);
    
    		for(i = 1; i <= n; i++)
    		{
    			scanf("%d %d", &post[i].l, &post[i].r);
    			flag[2*i-1] = post[i].l , flag[2*i] = post[i].r;
    		}
    		sort(flag + 1 , flag + 2*n + 1);
    		j = 1;
    		memset(ha, 0, sizeof(ha));
    		for(i = 1; i <= 2 * n; i++)
    		{
    			if(!ha[flag[i]])
    				ha[flag[i]] = j++;
    		}
    
    		BuildTree(1, 1, maxn);
    		for(i = 1; i <= n; i++)
    		{
    		    x = ha[post[i].l];
    		    y = ha[post[i].r];
    			Update(1, i, x, y);
    		}
    		memset(ha, 0, sizeof(ha));
    		ans = 0;
    		Query(1);
    		printf("%d
    ", ans);
    	}
    }
    
    void BuildTree(int i, int l, int r)
    {
    	tree[i].l = l;
    	tree[i].r = r;
    	tree[i].num = 0;
    	if(l == r) return;
    	int mid = (l + r) >> 1;
    	BuildTree(i << 1, l, mid);
    	BuildTree(i << 1 | 1, mid + 1, r);
    }
    
    void Update(int i, int num, int l, int r)
    {
    	if(tree[i].l == l && tree[i].r == r)
    	{
    		tree[i].num = num;
    		return;
    	}
    	if(tree[i].num != -1)
    	{
    		PushDown(i);
    		tree[i].num = -1;
    	}
    	int mid = (tree[i].l + tree[i].r) >> 1;
    	if(r <= mid) Update(i << 1, num, l, r);
    	else if(l > mid) Update(i << 1 | 1, num, l, r);
    	else
    	{
    		Update(i << 1, num, l, mid);
    		Update(i << 1 | 1, num, mid + 1, r);
    	}
    
    }
    
    void PushDown(int i)
    {
    	tree[i << 1].num = tree[i << 1 | 1].num = tree[i].num;
    }
    
    void Query(int i)
    {
    	if(tree[i].num != -1)
    	{
    		if(tree[i].num > 0 && ha[tree[i].num] == 0)
    		{
    			ha[tree[i].num] = 1;
    			ans++;
    		}
    		return;
    	}
    	else
    	{
    		Query(i << 1);
    		Query(i << 1 | 1);
    	}
    }
    

      

    
    









  • 相关阅读:
    邻接表(spfa模版)
    翻咸鱼(???)
    求逆序数
    Symmetry CSU
    Highways
    LightOJ
    G
    最长的斜坡。。。。
    快速幂取模
    二分
  • 原文地址:https://www.cnblogs.com/tenlee/p/4420104.html
Copyright © 2020-2023  润新知