zoukankan      html  css  js  c++  java
  • atcoder 131 F

    题目链接

    F - Must Be Rectangular!

    Time Limit: 2 sec / Memory Limit: 1024 MB

    Score :
    600
    points

    Problem Statement

    There are
    N
    dots in a two-dimensional plane. The coordinates of the i-th dot are ((x_i,y_i)).

    We will repeat the following operation as long as possible:

    Choose four integers a, b, c, d (a

    c
    ,
    b

    d
    )
    such that there are dots at exactly three of the positions
    (
    a
    ,
    b
    )
    ,
    (
    a
    ,
    d
    )
    ,
    (
    c
    ,
    b
    )
    and
    (
    c
    ,
    d
    )
    , and add a dot at the remaining position.

    We can prove that we can only do this operation a finite number of times. Find the maximum number of times we can do the operation.

    Constraints

    • 1≤N≤(10^5)

    ....

    详见题目链接

    思路

    将每一个点拆成两个点即横纵各一点

    然后将该两点连线

    好处

    自然将横坐标相等或纵坐标相等的若干点构成一个联通块

    是由(0,1),(1,1),(1,2),(1,0),(2,2)通过以上方法构成的

    统一将纵坐标加上一个10的目的是避免x,y不能相互区分

    然后 这样做了有什么用吗?

    答案是肯定的

    用并查集来维护

    for(i = 1;i <= n;i++)
    	{
    		int u,v;
          //u-x,v-y
    		scanf("%d%d",&u,&v);
    		f[FindSet(u)] = FindSet(v + MAXN);
    	}
    
    

    再设数组difx[]dify[]

    dif即difference用来统计横坐标或纵坐标的不同数的多少

    因为单纯点数 可能在行或列上有重合

    for(i = 1;i <= MAXN;i++)
    	difx[FindSet(i)]++;
    for(i = MAXN + 1;i <= MAXN * 2;i++)
    	dify[FindSet(i)]++;
    
    

    1(0,1)

    2(1,1)

    3(1,0)

    4(1,2)

    5(2,2)

    如图 的话 横坐标或纵坐标的不同数的多少各为3

    乘起来为整个矩阵点数 再减去已有的 就是答案

    但考虑到 可能不止一个联通块 所以需要一个枚举的操作

    for(i = 1;i <= MAXN * 2;i++)
    	ans += 1ll * difx[i] * dify[i];
    

    但聪明的同学可能会想到

    如果那些构不成(横或纵相等的在3个以下)的被误算了怎么办

    for(i = 1;i <= MAXN;i++)
    	difx[FindSet(i)]++;
    for(i = MAXN + 1;i <= MAXN * 2;i++)
    	dify[FindSet(i)]++;
    
    

    先前的代码 是加在祖先上的

    如果只有一个点(该点所在的行和列无它点)第一个FindSet(i) = 该点的纵坐标加MAXN

    可见只加了1 和 后面的减n是抵消了的

    然后 又会有同学提到 并查集的初始化

    	for(i = 1;i <= MAXN * 2;i++) f[i] = i;
    
    

    公平地给所有赋了值 包括一些实际上不存在的点

    那么是否有可能再次造成误算呢?

    这位同学 您又错了

    因为对于一个不存在的i
    difx[FindSet(i)]++;即difx[i]++;

    而ans加时加的是difx[FindSet(i)]*dify[FindSet(i)]

    细节

    difx的i和dify的i是错开枚举的

    即difx[i]>0定有dify[i]

    反之亦然

    所以不会干扰结果

    代码

    #include <cstdio>
    #include <vector>
    #include <algorithm>
     
    using namespace std;
    
    const int MAXN = 100000,MAX = 200005;
    int f[MAX],difx[MAX],dify[MAX];
    inline int FindSet(int a)
    {
    	if(a == f[a]) return a;
    	return f[a] = FindSet(f[a]);
    }
    int main()
    {
        int i,n; 
    	scanf("%d",&n);
    	for(i = 1;i <= MAXN * 2;i++) f[i] = i;
    	for(i = 1;i <= n;i++)
    	{
    		int u,v;
    		scanf("%d%d",&u,&v);
    		f[FindSet(u)] = FindSet(v + MAXN);
           //不能写成f[FindSet(u)] = v + MAXN;
           //否则会RE我也不知道为什么QAQ
    	}
    	for(i = 1;i <= MAXN;i++)
    		difx[FindSet(i)]++;
    	for(i = MAXN + 1;i <= MAXN * 2;i++)
    		dify[FindSet(i)]++;
    	long long ans = 0;
    	for(i = 1;i <= MAXN * 2;i++)
    		ans += 1ll * difx[i] * dify[i];
    	printf("%lld",ans - n);
        return 0;
    }
    
  • 相关阅读:
    【Python】【解决】UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 1: ordinal not in range(128)
    【小技巧】强制重启无线网卡,解决“区域中找不到无线网络,请确定您计算机上的无线开关已启用”问题
    【小技巧】9针USB转串口简易连通性测试,附25针转9针
    【ACM】HDU1008 Elevator 新手题前后不同的代码版本
    【Android】命令行jarsigner签字和解决找不到证书链错误
    LeetCode 【47. Permutations II】
    LeetCode 【46. Permutations】
    Python asyncio库的学习和使用
    LeetCode 【190. Reverse Bits】
    LeetCode 【21. Merge Two Sorted Lists】
  • 原文地址:https://www.cnblogs.com/resftlmuttmotw/p/11323198.html
Copyright © 2011-2022 走看看