题目传送门

题意:给出一个200 * 50000的像素点矩阵,执行50000次操作,每次把一个矩形/圆形/菱形/三角形内的像素点涂成指定颜色,问最后每种颜色的数量。

分析:乍一看,很像用线段树成段更新写,虽然复杂度有点大,但是也想不到其他的方法.这题可以巧妙地运用并查集来涂色.离线,从最后一个倒过来涂色,保证能涂上去的一定不会被覆盖,每次扫描一行,将一条线上的点都合并到右端点.

#include <bits/stdc++.h>
using namespace std; #define lson l, mid, o << 1
#define rson mid + 1, r, o << 1 | 1
typedef long long LL;
const int N = 5e4 + 2;
const int INF = 0x3f3f3f3f;
struct DSU {
int rt[N];
void clear(int n) {
fill (rt, rt+n, -1);
}
int Find(int x) {
return rt[x] == -1 ? x : rt[x] = Find (rt[x]);
}
void Union(int x, int y) {
rt[x] = y;
}
}dsu;
struct Point {
char str[20];
int xc, yc, a, b, c;
}p[N];
bool vis[N];
int ans[10];
int n, m, q; int squ(int x) {
return x * x;
} int cal(int x, int y) {
x = abs (x); y = abs (y);
return squ (x) + squ (y);
} int main(void) { //好题
while (scanf ("%d%d%d", &n, &m, &q) == 3) {
memset (ans, 0, sizeof (ans));
for (int i=0; i<q; ++i) {
scanf ("%s%d%d", &p[i].str, &p[i].xc, &p[i].yc);
if (p[i].str[0] == 'R') scanf ("%d%d%d", &p[i].a, &p[i].b, &p[i].c);
else scanf ("%d%d", &p[i].a, &p[i].c);
}
for (int i=0; i<n; ++i) {
dsu.clear (m); memset (vis, false, sizeof (vis));
for (int j=q-1; j>=0; --j) {
int left = 0, right = 0;
if (p[j].str[0] == 'C') {
if (squ (i - p[j].xc) > squ (p[j].a)) continue;
int tmp = (int) sqrt (1.0 * (squ (p[j].a) - squ (i - p[j].xc)));
left = p[j].yc - tmp; right = p[j].yc + tmp;
}
else if (p[j].str[0] == 'D') {
if (i < p[j].xc - p[j].a || i > p[j].xc + p[j].a) continue;
left = p[j].yc - p[j].a + abs (i - p[j].xc); right = p[j].yc + p[j].a - abs (i - p[j].xc);
}
else if (p[j].str[0] == 'R') {
if (i < p[j].xc || i > p[j].xc + p[j].a - 1) continue;
left = p[j].yc; right = p[j].yc + p[j].b - 1;
}
else if (p[j].str[0] == 'T') {
if (i < p[j].xc || i > p[j].xc + (p[j].a + 1) / 2 - 1) continue;
left = p[j].yc - p[j].a / 2 + (i - p[j].xc); right = p[j].yc + p[j].a / 2 - (i - p[j].xc);
}
if (left < 0) left = 0;
if (right >= m) right = m - 1;
int fa, fb = dsu.Find (right);
for (int k=left; k<=right; k=fa+1) { //paint a line
fa = dsu.Find (k);
if (!vis[fa]) {
ans[p[j].c]++; vis[fa] = true;
}
if (fa != fb) dsu.Union (fa, fb);
}
}
}
for (int i=1; i<=9; ++i) {
printf ("%d%c", ans[i], i == 9 ? '\n' : ' ');
}
} return 0;
}

  

并查集(涂色问题) HDOJ 4056 Draw a Mess的更多相关文章

  1. 转:并查集总结 例题:hdoj 1232 畅通工程

    引述之类的就免了,我们现在做题碰到的并查集基础题目大都是连通城市(或者村庄学校),接下来我们就称每一个城市为一个元素.我们解决此类题目运用的是树结构,每个集合用一棵树表示,而树的节点用于存储集合中的元 ...

  2. 【HDOJ】4056 Draw a Mess

    这题用线段树就MLE.思路是逆向思维,然后每染色一段就利用并查集将该段移除,均摊复杂度为O(n*m). /* 4056 */ #include <iostream> #include &l ...

  3. ZOJ 3544 / HDU 4056 Draw a Mess( 并查集好题 )

    方法参见:http://blog.acmol.com/?p=751 从最后一个线段开始倒着处理(因为之后的线段不会被它之前的线段覆盖),把这条线段所覆盖的所有线段编号合并到一个集合里,并以最左边线段编 ...

  4. 【数轴涂色+并查集路径压缩+加速】C. String Reconstruction

    http://codeforces.com/contest/828/problem/C [题意] [思路] 因为题目保证一定有解,所有优化时间复杂度的关键就是不要重复染色,所以我们可以用并查集维护区间 ...

  5. 并查集(HDOJ 1856)

    并查集   英文:Disjoint Set,即“不相交集合” 将编号分别为1…N的N个对象划分为不相交集合, 在每个集合中,选择其中某个元素代表所在集合. 常见两种操作: n       合并两个集合 ...

  6. HDOJ并查集题目 HDOJ 1213 HDOJ 1242

    Problem Description Today is Ignatius' birthday. He invites a lot of friends. Now it's dinner time. ...

  7. hdoj 1116 Play on Words 【并查集】+【欧拉路】

    Play on Words Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) T ...

  8. 并查集 HDOJ 1232 畅通工程

    题目传送门 /* 并查集(Union-Find)裸题 并查集三个函数:初始化Init,寻找根节点Find,连通Union 考察:连通边数问题 */ #include <cstdio> #i ...

  9. 并查集+树链剖分+线段树 HDOJ 5458 Stability(稳定性)

    题目链接 题意: 有n个点m条边的无向图,有环还有重边,a到b的稳定性的定义是有多少条边,单独删去会使a和b不连通.有两种操作: 1. 删去a到b的一条边 2. 询问a到b的稳定性 思路: 首先删边考 ...

随机推荐

  1. js方法类库封装的简易示例

    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></s ...

  2. Undefined symbols for architecture x86_64: ( linker command failed with exit code 1)

    当出现  linker command failed with exit code 1 (use -v to see invocation) 的错误总结,具体内容如下: Undefined symbo ...

  3. August 26th 2016 Week 35th Friday

    It always seems impossible until it's done. 在事情未完成之前,一切都看似不可能. When I was young, once I had to lift ...

  4. 容器配置jndi Tomcat为例

    context.xml 文件 <Resource name=" password="spsj" type="javax.sql.DataSource&qu ...

  5. 第三章 C#循环与方法

    第一节1-For循环入门 语法: for(条件表达式) { 执行语句 } 练习: 第三章作业1.写一个程序打印100到200的值;2.写一个程序从10打印到1:3.写一个程序打印10到30之间的所有偶 ...

  6. shell之数值运算

    Shell中声明变量默认是字符串, 要参与数值运算,可使用下面方式,简单,表示以数值方式.

  7. 动手动脑之小程序:TryAndCatch

    源代码 import java.util.InputMismatchException;import java.util.Scanner;public class TryAndCatch {publi ...

  8. 网站对话框开源脚本--ArtDialog V6.0

    初识对话框脚本觉得artDialog还是挺不错的开源的js脚本,最新版本都是V6.0 ,相对之前版本,artDialog的语法也发生很大的变化,windows对应的JS版本如下 点击下载 语法也发生变 ...

  9. Linux LVM全面实践

    1.磁盘分区 [root@ol6-121-rac1 ~]# fdisk /dev/sdb Device contains neither a valid DOS partition table, no ...

  10. 深入剖析iLBC的丢包补偿技术(PLC)

    转自:http://blog.csdn.net/wanggp_2007/article/details/5136609 丢包补偿技术(Packet Loss Concealment——PLC)是iLB ...