uva 1493 - Draw a Mess(并查集)

题目链接:uva 1493 - Draw a Mess

题目大意:给定一个矩形范围,有四种上色方式,后面上色回将前面的颜色覆盖,最后问9种颜色各占多少的区域。

解题思路:用并查集维护每个位置对应下一个可以上色的位置。然后将上色倒转过来处理,就解决了颜色覆盖的问题。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>

using namespace std;
const int maxr = 205;
const int maxc = 50005;

int N, M, Q, cnt[15];
int f[maxr][maxc];

struct Order {
    int sign, star, end;
    int x, y, r, w, c;
    void set (int sign, int x, int y, int c, int r, int w = 0) {
        this->sign = sign;
        this->x = x;
        this->y = y;
        this->c = c;
        this->r = r;
        this->w = w;
        del_star();
    }

    void del_star () {
        if (sign < 2) {
            star = max(x - r, 0);
            end = min(x + r, N - 1);
        } else if (sign == 2) {
            r = (r + 1) / 2 - 1;
            star = x;
            end = min(x + r, N-1);
        }
    }

}op[maxc];

int getfar (int* far, int x) {
    return x == far[x] ? x : far[x] = getfar(far, far[x]);
}

int style (char ch) {
    if (ch == ‘C‘)
        return 0;
    else if (ch == ‘D‘)
        return 1;
    else if (ch == ‘T‘)
        return 2;
    else
        return 3;
}

void init () {
    memset(cnt, 0, sizeof(cnt));
    for (int i = 0; i <= M; i++) {
        for (int j = 0; j < N; j++)
            f[j][i] = i;
    }

    char s[20];
    int x, y, r, c, w;
    for (int i = 1; i <= Q; i++) {
        scanf("%s", s);
        if (s[0] != ‘R‘) {
            scanf("%d%d%d%d", &x, &y, &r, &c);
            op[i].set(style(s[0]), x, y, c, r);
        } else {
            scanf("%d%d%d%d%d", &x, &y, &r, &w, &c);
            op[i].set(style(s[0]), x, y, c, r, w);
        }
    }
}

inline int get_R (int r, int x, int i, int sign) {
    if (sign == 0)
        return (int)sqrt(1.0 * r * r - 1.0 * (x - i) * (x - i));
    else if (sign == 1)
        return r - abs(x - i);
    else if (sign == 2)
        return r - (i - x);
    return 0;
}

int count (int x, int y, int r, int star, int end, int sign) {
    int ret = 0;
    for (int i = star; i <= end; i++) {
        int R = get_R(r, x, i, sign);

        int mv = max(y - R, 0);
        while (mv = getfar(f[i], mv), abs(mv - y) <= R && mv < M) {
            ret++;
            f[i][mv] = mv+1;
        }
    }
    return ret;
}

int count_rec (int x, int y, int r, int l) {
    int ret = 0;
    for (int i = x; i <= x + r - 1 && i < N; i++) {
        int mv = y;
        while (mv = getfar(f[i], mv), abs(mv - y) < l && mv < M) {
            ret++;
            f[i][mv] = mv+1;
        }
    }
    return ret;
}

void solve () {

    for (int i = Q; i; i--) {
        int& col = cnt[op[i].c];
        if (op[i].sign == 3)
            col += count_rec(op[i].x, op[i].y, op[i].r, op[i].w);
        else
            col += count(op[i].x, op[i].y, op[i].r, op[i].star, op[i].end, op[i].sign);
    }

    for (int i = 1; i <= 9; i++)
        printf("%d%c", cnt[i], i == 9 ? ‘\n‘ : ‘ ‘);
}

int main () {
    while (scanf("%d%d%d", &N, &M, &Q) == 3) {
        init();
        solve();
    }
    return 0;
}
时间: 2024-10-22 03:48:16

uva 1493 - Draw a Mess(并查集)的相关文章

UVA - 1493 Draw a Mess 并查集+压缩图

题目大意:给出n*m的点,可以在上用不同颜色的笔画矩形,菱形,等腰三角形和圆形,因为是一个一个画的,所以有的点会被覆盖掉,原先的颜色就会被覆盖掉了.现在给出每个人画的图案和顺序,问最后每种颜色占了多少个点 解题思路:如果直接暴力的话就会TLE 为了防止被覆盖,就倒着画,如果该点被占有了,就不可以再画了 我们用并查集将每一个点所能到达的最右端的点纪录下来,将那些被使用过的点并起来,然后依次从上往下扫 参考了学长的代码... #include<cstdio> #include<cstring

UVA1493 - Draw a Mess(并查集)

题目链接 题目大意:一个N * M 的矩阵,每次你在上面将某个范围上色,不论上面有什么颜色都会被最新的颜色覆盖,颜色是1-9,初始的颜色是0.最后输出这个矩形中,每个颜色有多少个.某个范围这个分为了四种,圆,矩形,菱形,还有正三角形(倒着的).注意这题的边界,不能超出这个矩形,很容易越界. 解题思路:因为题的矩阵范围是200 * 50000,然后操作又是50000,这样三个相乘,即使给60s也是不够的.因为行的数目比较少,如果每次都能将这一行哪个没处理过直接拿出来,而不用一个一个判断就快很多了,

uva 11987 Almost Union-Find (并查集)

题目大意: 三个操作. 1. 合并两个集合 2.把第一个元素放到第二个集合里 3.输出集合的数量和和.. 思路分析: 要用p记录这个元素所在集合编号,然后用编号建立并查集. #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> using namespace std; typedef long long LL; int set[111111]; int cn

UVA 1455 - Kingdom(线段树+并查集)

UVA 1455 - Kingdom 题目链接 题意:给定一些城市坐标点,连在一起的城市称为一个州,现在用两种操作,road表示把城市a,b建一条路,line表示询问一个y轴上穿过多少个州,和这些州共包含多少个城市 思路:利用并查集维护每个州的上界和下界还有城市个数,然后每次加进一条路的时候,根据两个集合的位置可以处理出区间的州和城市数如何进行加减,然后利用线段树搞就可以了 代码: #include <cstdio> #include <cstring> #include <

UVA 572 油田连通块-并查集解决

题意:8个方向如果能够连成一块就算是一个连通块,求一共有几个连通块. 分析:网上的题解一般都是dfs,但是今天发现并查集也可以解决,为了方便我自己理解大神的模板,便尝试解这道题目,没想到过了... 1 #include <cstdio> 2 #include <iostream> 3 #include <sstream> 4 #include <cmath> 5 #include <cstring> 6 #include <cstdlib&

UVA 12232 - Exclusive-OR(带权并查集)

UVA 12232 - Exclusive-OR 题目链接 题意:有n个数字.一開始值都不知道,每次给定一个操作,I a v表示确认a值为v,I a b v,表示确认a^b = v,Q k a1 a2 a3 ... ak.表示推断这些数字的异或值是否能确定.能确定就输出值,假设有矛盾就停止 思路:带权并查集,权表示和父结点的异或值,那么多数推断的时候,仅仅要全部数字和他的父结点的异或值的异或值.假设父结点的个数是偶数个.那么依据异或的性质能抵消掉,是能够判定的.假设不为偶数,就是不能判定. 注意

UVA 1329 Corporative Network【并查集】

题目链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4075 题意: 有n个结点,開始都是单独的结点,如今有I操作和E操作,I u v表示吧u的父亲结点设为,距离为|u - v| % 1000,E操作询问u到根的距离 代码: #include <stdio.h> #include <iostream> #in

UVA 11987 Almost Union-Find(并查集之五)

问题描述: 第一行为两个整数:n和m分别代表开始集合的个数和命令的个数. 初始化每个集合只有一个元素,从1到n一共n个集合,第i个集合里面的那一个元素值为i. 有三个命令:1命令后面紧跟两个参数p,q代表把p和q所在集合合并. 2命令同样两个参数,假设p,q代表把p单独从自己集合中拿出放到q集合里面. 1命令如果p,q已经在同一个集合里面,则忽略此命令,2命令同理. 3命令为查询命令,后面紧跟一个参数p,查询p所在集合中元素的个数和所有元素之和. Sample Input 5 71 1 22 3

hdu 4056 Draw a Mess(数据结构-并查集)

Draw a Mess Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 864    Accepted Submission(s): 180 Problem Description It's graduated season, every students should leave something on the wall, so.