zoukankan      html  css  js  c++  java
  • Section 3.1 Shaping Regions

    卡这题卡了一天左右,不会做额,找了不少的代码和解说,发现NOCOW这里很不错,有大牛在这里写方法,可以拓宽思路,这几个1,2,3还不错,看懂了,和HDU1543是同一道题,就说说题意和方法吧。

    给定一个A*B的矩形,A<10^4,B<10^4,然后可以往这个矩形上涂矩形状的颜色,矩形和X,Y轴平行,如果涂到同一个地方,则覆盖原来的颜色,颜色C<2500,有N<1000个矩形,求最后剩下的各个颜色的个数。

    有很多方法了,矩形分割,线段树,并查集优化,等等,但调了线段树来看,顺便复习下线段树。用二维实现的话,空间很紧,于是就牺牲时间换空间,用一维的线段树来实现,离散化然后扫描线。我将矩形的x方向的值离散化掉,然后扫描从左到右,对于每两个线x1,x2,先创建一颗线段树,按读入顺序遍历矩形,判断是否覆盖x1,x2,如果覆盖,则该矩形对该区间覆盖有效,则将该Y方向上的线段插入线段树中,之后,统计树上的颜色值。

    想到的有两个细节:

    1. 遍历矩形的顺序可以按实现的方法来选择,反过来的话,即涂过的地方就不涂了.

    2. 原先的矩形都是颜色1,可以事后再统计.

    这样子就可以通过USACO上的题了,注意在线段树上涂色的方法实现,详情见代码中加*处,线段树的原理之一就是基于子树就是当前数的子集划分,由它代替所有子树,如果没必要时,在当前树这儿就可以停止了,但如果继续深入的话,要注意子树的数据是否是更新的,如果不是更新的,要注意更新。下面的代码在第11组数据处花了1.7+s时间,可以把Y方向和颜色C都离散化掉,应该会快的,就没改了。

    接下来把矩形分割的方法学一下,线段树+离散化+扫描线的代码如下:

    /*
    ID: litstrong
    PROG: rect1
    LANG: C++
    */
    #include <iostream>
    #include <string>
    #include <vector>
    #include <set>
    #include <math.h>
    #include <queue>
    #include <algorithm>
    #include <string.h>
    #include <stdio.h>
    using namespace std;
     
    const int MAXN = 10005;
    const int MAXC = 2505;
     
    int c_cnt[MAXC];
    int c_ans[MAXC];
    int x_line[MAXN * 2];
     
    class CSEG
    {
    public:
        int L, R, C;
        //C表示颜色
    public:
        CSEG() {}
        CSEG(int _L, int _R, int _C) : L(_L), R(_R), C(_C) {}
    };
     
    //区间树,线段树的变形
    class CSEGTREE
    {
    public:
        CSEG segs[MAXN * 5];
    public:
        void Build(int root, int L, int R)
        {
            segs[root] = CSEG(L, R, 1);
            int M = (L + R) / 2;
            //printf("%d %d %d\n", root, L, R);
            if(R - L > 1) //非叶子的话扩展
            {
                if(L < M)  Build(2 * root, L, M);
                if(M < R)  Build(2 * root + 1, M, R);
            }
        }
        void Insert(int root, int line_L, int line_R, int C)
        {
            //segs[root].L <= segs[root].R
            //printf("%d %d %d %d %d\n", root, segs[root].L, segs[root].R, line_L, line_R);
            if(line_L <= segs[root].L && line_R >= segs[root].R)    //完全覆盖
            {
                segs[root].C = C;    //下面的不更新了,之后再更新
                return;
            }
            if(segs[root].C != -1)
            {
                if(segs[root].C == C)  return;    //剪枝
                //否则扩展,记住这时往下更新
                segs[2 * root].C = segs[2 * root + 1].C = segs[root].C;    //******
            }
            segs[root].C = -1;    //部分覆盖,标记为混色,用于查询时的优化
            int M = (segs[root].L + segs[root].R) / 2;
            if(line_R > M)  Insert(2 * root + 1, line_L, line_R, C);
            if(line_L < M)  Insert(2 * root, line_L, line_R, C);
        }
        void Query(int root)
        {
            if(segs[root].C != -1)
            {
                c_cnt[segs[root].C] += (segs[root].R - segs[root].L);
                return;
            }
            Query(2 * root);
            Query(2 * root + 1);
        }
    };
     
    class CRECT
    {
    public:
        int nx, mx, ny, my, c;
    public:
        CRECT() {}
        CRECT(int _nx, int _mx, int _ny, int _my, int _c) :
        nx(_nx), mx(_mx), ny(_ny), my(_my), c(_c) {}
    }rect[MAXN];
     
    int main()
    {
        freopen("rect1.in", "r", stdin);
        freopen("rect1.out", "w", stdout);
     
        int A, B, N;
        scanf("%d%d%d", &A, &B, &N);
        for(int i = 0; i < N; i++)
        {
            int nx, mx, ny, my, c;
            scanf("%d%d%d%d%d", &nx, &ny, &mx, &my, &c);
            rect[i] = CRECT(min(nx, mx), max(nx, mx), min(ny, my), max(ny, my), c);
            x_line[2 * i] = nx;
            x_line[2 * i + 1] = mx;
        }
        sort(x_line, x_line + 2 * N);
        memset(c_ans, 0, sizeof(c_ans));
     
        CSEGTREE tree;
        for(int i = 1; i < 2 * N; i++)
        {
            if(x_line[i - 1] == x_line[i])  continue;
            tree.Build(1, 0, B);
            //printf("Build ok\n");
            memset(c_cnt, 0, sizeof(c_cnt));
            for(int j = 0; j < N; j++)
            {
                if(rect[j].nx <= x_line[i - 1] && 
                    rect[j].mx >= x_line[i])
                {
                    tree.Insert(1, rect[j].ny, rect[j].my, rect[j].c);
                    //printf("Insert ok\n");
                }
            }
            tree.Query(1);
            for(int j = 0; j < MAXC; j++)
            {
                c_ans[j] += c_cnt[j] * (x_line[i] - x_line[i - 1]);
            }
            //printf("#%d, %d, %d*%d=%d\n", c_cnt[1], c_cnt[3], c_cnt[2], (x_line[i] - x_line[i - 1]), c_cnt[2] * (x_line[i] - x_line[i - 1]));
        }
        c_ans[1] += (A - x_line[2 * N - 1] + x_line[0]) * B;
        for(int i = 0; i < MAXC; i++)
        {
            if(c_ans[i])  printf("%d %d\n", i, c_ans[i]);
        }
    }
  • 相关阅读:
    Vsftpd 3.0.2 正式版发布
    Putdb WebBuilder 6.5 正式版本发布
    SoaBox 1.1.6 GA 发布,SOA 模拟环境
    pynag 0.4.6 发布,Nagios配置和插件管理
    Percona Playback 0.4,MySQL 负荷回放工具
    xombrero 1.3.1 发布,微型 Web 浏览器
    Hypertable 0.9.6.4 发布,分布式数据库
    libmemcached 1.0.11 发布
    CryptoHeaven 3.7 发布,安全邮件解决方案
    Android Activity生命周期
  • 原文地址:https://www.cnblogs.com/litstrong/p/1971189.html
Copyright © 2011-2022 走看看