您的位置:首页 > 其它

矩形填补

2016-07-08 15:42 253 查看

问题描述 Problem Description

给定平面 n 个黑点,如果平面一个边平行于坐标轴的矩形 3 个角是黑色的那么就把那个矩形的第 4 个角改成黑色,最后平面上将会有多少个黑点

输入描述 Input Description

第一行一个整数 n ,表示最初有 n 个点

接下来 n 行,每行两个整数 xi,yi,表示第 i 个点的坐标

输出描述 Output Description

一个整数,表示最后有多少个点

输入样例 Sample Input

[1]

3

1 1

1 2

2 2

[2]

5

0 0

1 0

0 1

1 2

2 1

输出样例 Sample Output

[1]

4

[2]

9

数据范围 Data Size

30% 的数据 n≤100

100% 的数据 n≤2∗105;|xi|,|yi|≤109

分析 I Think

因为 x,y 十分巨大,所以要用离散化,弱弱的我还只会用 map 。

对于任意一个点 (xi,yi) ,我们将 xi 与 yi 连边,这样子,如果存在 (x1,y1),(x1,y2),(x2,y1) 的话,第四个点 (x2,y2) 也被连在一起了。

至于统计点的数量,如果 a 个 x 值和 b 个 y 值被连在一起,那么总计有 a∗b 个点,记 fi 表示以 i 为根的树中有多少个 x 值, gi 表示以 i 为根的树中有多少个 y 值, 最后答案就是 ∑fi∗gi ,每次合并时顺便合并一下 f,g 就可以了。

代码 Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;

typedef long long LL;

const LL add = 10000000000;

int father[400040];
int f[400040];
int g[400040];
map<LL,int>turn;
LL n,t;

void read(LL &);
int find(int);
void uni(int,int);

int main(){

read(n);

for(int i=1;i<=(n<<1);++i)
father[i] = i;

for(LL i=1,x,y;i<=n;++i){
read(x);
read(y);
y += add;
if(turn.find(x) == turn.end()){
turn.insert(pair<LL,int>(x,++t));
f[t] = 1;
g[t] = 0;
}
if(turn.find(y) == turn.end()){
turn.insert(pair<LL,int>(y,++t));
f[t] = 0;
g[t] = 1;
}
uni(turn[x],turn[y]);
}

LL ans = 0;
for(int i=1;i<=t;++i)
if(father[i] == i)
ans += (LL)f[i]*g[i];

printf("%lld",ans);

return 0;

}

void read(LL &_in){

_in = 0;
LL flag = 1;
char ch = getchar();

while(ch!='-' && (ch>'9'||ch<'0'))
ch = getchar();
if(ch == '-'){
flag = -1;
ch = getchar();
}
while(ch>='0' && ch<='9'){
_in = _in*10+ch-'0';
ch = getchar();
}

_in *= flag;

}

int find(int x){

if(x != father[x])
father[x] = find(father[x]);

return father[x];

}

void uni(int x,int y){

int p = find(x);
int q = find(y);

if(p == q)
return ;

f[q] += f[p];
g[q] += g[p];
f[p] = g[p] = 0;
father[p] = q;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: