UVA 1493 Draw a Mess(并查集+set)
这题我一直觉得使用了set这个大杀器就可以很快的过了,但是网上居然有更好的解法,orz。。。
题意:给你一个最大200行50000列的墙,初始化上面没有颜色,接着在上面可能涂四种类型的形状(填充):
圆 :给你圆心坐标,半径,颜色 (1->9)
菱形 :中心坐标,中心向四方的最大值,颜色(1->9)
矩形 :左上角坐标,长和宽,颜色(1->9)
等腰三角形:底边中心坐标,底边长(+1再/2 就是高),颜色(1->9)
其中输入的坐标一定在墙上,但是其他地方可能越界,所以要处理好。
最后输出每种颜色的个数
开始觉得就是一个比较麻烦的暴力嘛,但是一看数据5000个询问。。。好吧想想优化。
我发现虽然总个数特别的多,但是如果我们把每次已经涂色的地方记录下来,下次不用寻找,这样就节约时间了。诶,等等,不对呀,不是前者要覆盖后者吗?所以我们要离线处理倒序涂色。
然后我们可以看到,行列分配得不均匀,如果我们枚举列话还是会超时(每次图形都列很多的情况)。所以我们枚举行,初始每行都使用一个并查集连接右边一个没被涂色的列。涂色后就把前面最后一个没涂色的连上后面最前一个没涂色的(前后都多加一个,避免特判),这样下次就可以不找这一段了,但是我们寻找最前面一个在图形范围内没涂色时又有可能会超时。所以我们上set:添加删除数据O(log2n),查询大于等于关键字的位置又是O(log2n)。每个图形找到涂色行中列的范围,使用set查询范围内最前面的一个,然后使用枚举没有涂色的列,注意这儿每次枚举后set内都要删除。
还有就是这题坑死了,三角形的底边长居然没按照题意,存在偶数。。。
代码比较挫
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<string>
#include<cstdio>
#include<cstring>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define eps 1E-8
/*注意可能会有输出-0.000*/
#define Sgn(x) (x<-eps? -1 :x<eps? 0:1)//x为两个浮点数差的比较,注意返回整型
#define Cvs(x) (x > 0.0 ? x+eps : x-eps)//浮点数转化
#define zero(x) (((x)>0?(x):-(x))<eps)//判断是否等于0
#define mul(a,b) (a<<b)
#define dir(a,b) (a>>b)
typedef long long ll;
typedef unsigned long long ull;
const int Inf=<<;
const double Pi=acos(-1.0);
const int Mod=1e9+;
const int Max=;
set<int> se[];//每行建立一个set查询
set<int>::iterator it;
int fat[][Max],ans[];
struct node
{
int xx1,yy1,l,w,c;
char str[];
} blo[Max];
void Init(int n,int m)
{
memset(ans,,sizeof(ans));
for(int i=; i<=n+; ++i)
{
se[i].clear();
for(int j=; j<=m+; ++j)
{
se[i].insert(j);
fat[i][j]=j+;//初始化每行每个点指向下一个点,多加两个点避免边界特殊处理
}
fat[i][m+]=m+;
}
return;
}
int nmax(int a,int b)
{
return a>b?a:b;
}
int nmin(int a,int b)
{
return a>b?b:a;
}
int stax,ennx,stay,enny,tem;
void Crc(int n,int m,node &p,int i)//圆
{
tem=int(sqrt(double(p.w-i+p.xx1)*(p.w+i-p.xx1)));
it=se[i].lower_bound(nmax(p.yy1-tem,));
--it;
stay=*it;
enny=nmin(tem+p.yy1,m)+;
return;
}
void Dam(int n,int m,node &p,int i)//菱形
{
tem=p.w-abs(p.xx1-i);
it=se[i].lower_bound(nmax(p.yy1-tem,));
--it;
stay=*it;
enny=nmin(tem+p.yy1,m)+;
return;
}
void Rtg(int n,int m,node &p,int i)//矩形
{
it=se[i].lower_bound(nmax(p.yy1,));
--it;
stay=*it;
enny=nmin(p.w+p.yy1,m+);
return;
}
void Trg(int n,int m,node &p,int i,int pp)//三角形
{
tem=pp-(p.w+)/+;
it=se[i].lower_bound(nmax(p.yy1+tem,));
--it;
stay=*it;
enny=nmin(p.yy1-tem,m)+;
return;
}
void Solve(int n,int m,int q)
{
for(int i=q-; i>=; --i)
{
if(blo[i].str[]=='C')
{
stax=nmax(blo[i].xx1-blo[i].w,);
ennx=nmin(blo[i].w+blo[i].xx1,n)+;
}
else if(blo[i].str[]=='D')
{
stax=nmax(blo[i].xx1-blo[i].w,);
ennx=nmin(blo[i].w+blo[i].xx1,n)+;
}
else if(blo[i].str[]=='R')
{
stax=blo[i].xx1;
ennx=nmin(blo[i].xx1+blo[i].l,n+);
}
else
{
stax=blo[i].xx1;
ennx=nmin(blo[i].xx1+(blo[i].w+)/-,n)+;
}
int j;
for(int ii=stax; ii<ennx; ++ii)
{
if(blo[i].str[]=='C')
Crc(n,m,blo[i],ii);
else if(blo[i].str[]=='D')
Dam(n,m,blo[i],ii);
else if(blo[i].str[]=='R')
Rtg(n,m,blo[i],ii);
else
Trg(n,m,blo[i],ii,ii-stax);
j=fat[ii][stay];
while(j<enny)
{
se[ii].erase(j);
j=fat[ii][j];//并查集可以跳过已经涂色过的
++ans[blo[i].c];
fat[ii][stay]=j;
}
}
}
return;
}
int main()
{
int n,m,q;
while(~scanf("%d %d %d",&n,&m,&q))
{
Init(n,m);
for(int i=; i<q; ++i)
{
scanf("%s",blo[i].str);
if(blo[i].str[]=='R')
scanf("%d %d %d %d %d",&blo[i].xx1,&blo[i].yy1,&blo[i].l,&blo[i].w,&blo[i].c);
else
scanf("%d %d %d %d",&blo[i].xx1,&blo[i].yy1,&blo[i].w,&blo[i].c);
++blo[i].xx1,++blo[i].yy1;
}
Solve(n,m,q);
for(int i=; i<; i++)
printf("%d%c",ans[i],i==?'\n':' ');
}
return ;
}
UVA 1493 Draw a Mess(并查集+set)的更多相关文章
- uva 1493 - Draw a Mess(并查集)
题目链接:uva 1493 - Draw a Mess 题目大意:给定一个矩形范围,有四种上色方式,后面上色回将前面的颜色覆盖,最后问9种颜色各占多少的区域. 解题思路:用并查集维护每一个位置相应下一 ...
- UVA1493 - Draw a Mess(并查集)
UVA1493 - Draw a Mess(并查集) 题目链接 题目大意:一个N * M 的矩阵,每次你在上面将某个范围上色,不论上面有什么颜色都会被最新的颜色覆盖,颜色是1-9,初始的颜色是0.最后 ...
- Draw a Mess (并查集)
It's graduated season, every students should leave something on the wall, so....they draw a lot of g ...
- UVA 572 油田连通块-并查集解决
题意:8个方向如果能够连成一块就算是一个连通块,求一共有几个连通块. 分析:网上的题解一般都是dfs,但是今天发现并查集也可以解决,为了方便我自己理解大神的模板,便尝试解这道题目,没想到过了... # ...
- 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 ...
- UVA 1160 - X-Plosives 即LA3644 并查集判断是否存在环
X-Plosives A secret service developed a new kind ofexplosive that attain its volatile property only ...
- UVA 11987 Almost Union-Find (并查集+删边)
开始给你n个集合,m种操作,初始集合:{1}, {2}, {3}, … , {n} 操作有三种: 1 xx1 yy1 : 合并xx1与yy1两个集合 2 xx1 yy1 :将xx1元素分离出来合到yy ...
- UVA - 1160(简单建模+并查集)
A secret service developed a new kind of explosive that attain its volatile property only when a spe ...
- UVa 1455 Kingdom 线段树 并查集
题意: 平面上有\(n\)个点,有一种操作和一种查询: \(road \, A \, B\):在\(a\),\(b\)两点之间加一条边 \(line C\):询问直线\(y=C\)经过的连通分量的个数 ...
随机推荐
- Ubuntu16.04下搜狗输入法、Sublime Text 3的安装
Ubuntu16.04下搜狗输入法.Sublime Text 3的安装 一.搜狗输入法 1. 安装中文语言 默认在Ubuntu16.04下是没有中文的,需要安装中文,在System Settings- ...
- android开发系列之aidl
aidl在android开发中的主要作用就是跨进程通讯来着,说到进程相比很多人都是非常熟悉了,但是为什么会有跨进程通讯这个概念呢?原来在android系统中,有这么一套安全机制,为了各个Apk数据的独 ...
- storm RollingTopWords 实时top-N计算任务窗口设计
转发请注明原创地址 http://www.cnblogs.com/dongxiao-yang/p/6381037.html 流式计算中我们经常会遇到需要将数据根据时间窗口进行批量统计的场景,窗口性质一 ...
- Android Studio gradle 文件中 ${supportLibVersion} 用法
一般我们在项目中的gradle会添加如下库文件 dependencies { compile 'com.android.support:appcompat-v7:23.1.0' compile 'co ...
- PMD:Java源代码扫描器
PMD是一个开源代码分析器.可以查找常见编程缺陷,比如未使用的变量.空catch代码块.不必要的对象创建等.支持Java.JavaScript.PLSQL.Apache Velocity.XML.XS ...
- Linux守护进程简单介绍和实例具体解释
Linux守护进程简单介绍和实例具体解释 简单介绍 守护进程(Daemon)是执行在后台的一种特殊进程.它独立于控制终端而且周期性地执行某种任务或等待处理某些发生的事件.守护进程是一种非常实用的进程. ...
- 用C#来学习唐诗三百首和全唐诗
Begin 最近把项目做完了,闲来无事,就想做点好玩的事情,刚好前几天下载了[唐诗三百首]和[全唐诗]这两个txt文件,正好用C#来整理一下. 然后导出QData格式,可以给其他软件读取. 以后弄个开 ...
- CAFFE学习笔记(一)Caffe_Example之训练mnist
0.参考文献 [1]caffe官网<Training LeNet on MNIST with Caffe>; [2]薛开宇<读书笔记4学习搭建自己的网络MNIST在caffe上进行训 ...
- 什么是Mocking framework?它有什么用?(转)
今天我想讲下关于mocking frameworks,并且解释下他为什么有用处.我将给你们展示用和不用mocking framework两种测试方法. 假设我们已经有了一个Driver类: publi ...
- Arrays数组工具类中存在的坑!
以下是一个坑: 看到使用asList时候,可以返回一个集合,当然集合拥有CRUD的特性: 代码中使用 了add和remove时候均报错:Exception in thread "main&q ...